aspose file tools*
The moose likes I/O and Streams and the fly likes list files names a litle Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » I/O and Streams
Bookmark "list files names a litle "counting" problem" Watch "list files names a litle "counting" problem" New topic
Author

list files names a litle "counting" problem

maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42
thank you very much to Greg for having helped me here,
http://www.coderanch.com/t/538574/Streams/java/renaming-all-files-one-dir#2443221

I have another problem:

if I have files

1.jpg, 2.jpg, 4.jpg, 4.jpg (etc.. 3 left out on purpose)

and I want to rename them
1.jpg, 2.jpg, 3.jpg, 4.jpg, etc... (for a situation in which I remove one image and need to rename all imgs in folder again...)

but problem is: programming languages have this **very quirky** way of counting, that drives me nuts:

1, 10, 11, 12, 13... (man.. whoever thought of this??? nobody counts like that...;~)

so when I list files before rename the list is:

1.jpg
10.jpg
11.jpg

etc..

so when I rename what happens is 10.jpg gets renamed 2.jpg... etc...

what is solution.. thank you..


EDIT:

I can't just say something like



because it has to detect which files are missing (for example if I have 1.jpg, 2.jpg, 5.jpg etc.. hope you get my drift....)

----------------
(PS: why is font in this textarea so small? it's set to 11px; that's small, could the Javaranch "powers that be" set it a bit larger??? ;-)


Hunter McMillen
Ranch Hand

Joined: Mar 13, 2009
Posts: 492

That isn't the programming language's way of counting, it is your file systems way of organizing directories. Those image files are sorted by the first letter or digit then sorted by the second letter or digit, ...etc...

You can store all of the files in the directory in an array, then sort them yourself to see which ones are missing.

Hunter


"If the facts don't fit the theory, get new facts" --Albert Einstein
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

But you can't sort on filename, because alphabetically 10 comes before 2. You need to use your own Comparator implementation that retrieves the number from the filename and uses that to sort on. A quick and dirty attempt:


SCJP 1.4 - SCJP 6 - SCWCD 5 - OCEEJBD 6
How To Ask Questions How To Answer Questions
Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

The File.list() and File.listFiles() methods don't guarantee sort order at all, so the fact you're getting the files in strict alphabetical order is still more than you can count on. (Ha! count on. I made a funny.) You want to get the array of file name Strings or array of Files and then use: Arrays.sort(files, myComparator), where myComparator is an instance of something that will sort your files the way you want. Rob's given you a good class that will work on Files. Here's a more general one that works on all kinds of Strings containing numbers: NaturalOrderComparator. Either class could be modified to work on Files or String file names as needed.
maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42
thank you all for yr responses.. I couldn't bring my Macbook Pro to work today (since on Wed's I go to the gym after work...;-) so I installed java jdk/jre in my xp machine at work.. but when run java class get major.minor version 50.0 error.. (can compile classes fine, compiled class NaturalOrderComparator w/no problems.. (had to change that constructor to public though.. otherwise how do I use it in another class?? ;-)

I put C:\Program Files\Java\jdk1.6.0_25\bin in path; both javac.exe and java.exe are in there.. so not sure what the problem is.. (have done this java stuff in windows many times; have had a mac for only 8 months..)

will have to revisit when am on my mac again...


thank you very much....
Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

Sometimes Windows will have a version of Java in the System32/bin and if you're not careful setting up your PATH variable, that's the one that will get used. The error you're getting means you are running the program with an earlier version of Java than the one you compiled with, so I'd guess that's what's happening.

NaturalOrderComparator contains a public static instance of itself, so you don't really need to construct it. It's following a pattern called Singleton, although it implements that pattern in a non-standard way.
Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

Greg Charles wrote:Sometimes Windows will have a version of Java in the System32/bin and if you're not careful setting up your PATH variable, that's the one that will get used.

That's why sometimes it's wise to put the Java folder at the start of the PATH, to make sure the system will find the explicit Java executable instead of the system32 Java executable.
maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42
thank you all very much.. it turns out there were other Java installs (one of them the root was Oracle, it also contained a Java JRE and its bin dir was in the path; I just removed it...)

back on my mac.. please help me out.. not sure how to this class (either NaturalOrderComparator or other code posted by Rob Spoor (don't get how comparing file names help sort them.. let's say I have file 1.jpg through 16.jpg but no 5.jpg, so need to rename all files in dir so nos. go from 1 to 15... (the reason I didn't know about this problem earlier is I had tested all the time with less than 10 imgs in the test dir -- oh man... )

in this code



what is File2?? I don't see any sort method in this code... ( I'm not an expert Java programmer, this is for a personal project..)

here's my code: http://mayacove.com/dev/java/ren.txt... how/where would I incorporate this sorting code into it?
since Greg said he couldn't see the code @ this url the other day (?) I have posted a screenshot also http://mayacove.com/dev/java/ren.jpg

man, this is so frustrating.. so the hardest part of the program I haven't even tackled yet... :-( yikes....

thank you...

Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

Sorting algorithms are a really interesting topic in computer science. There are many different ones ... quick sort, bubble sort, insertion sort, heap sort, merge sort, radix sort ... simple ones, complex ones, fast ones, slow ones, fat ones, skinny ones, hot dogs, Armor hot dogs.

Anyway, they all have one thing in common. They all need to compare one object to another to determine which one is bigger. That's the job of the the Comparator. (You also have the option of implementing Comparable instead.) The compare() method takes two objects, and return -1 if the first should be sorted first in a list, 1 if it should be second, or 0 if two objects are equal and it doesn't matter which is first. When you sort a list, the compare method will be called many times, each time using two elements of the list you're sorting, until finally, like magic, you have a sorted list. So that's why there's a file1 and a file2.

As for where to put it, I told you to call Arrays.sort(myFiles, myComparitor). I'm sticking with that suggestion. You know how to get an array of files or file names and you know how to get the comparitor, so you're all set. Once you get the sorted list of files, you can rename them just like you were doing for the shuffled list from the previous thread.

maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42

oh brother.. this is really hard (I know it doesn't seem like this to you experts, but it is if you're not familiar w/this..)

I have now:





is this what you meant? (everything is in method 'main' -- if I put comparator decl. outside method 'main' I get infamous "non-static variable cannot be referenced from a static context" error message.. I had forgotten about this..(sigh....) so consulted my notes.. so put everything outside method "main" and did:



but then get error: that class "comparator" cannot be found...

(sorry not sure if I have to create an instance of what Rob sent (Comparator<File> comparator = new Comparator<File>()) or is that already an instance I can use by doing



if I put everything inside method 'main', as mentioned above, I get error:

ren.java:79: cannot find symbol
symbol : method sort(java.lang.String,java.util.Comparator<java.io.File>)
location: class java.util.Arrays
Arrays.sort(currFileNames[i], comparator);
^

my imports:



this should cover everything I need, right?

thank you very much....







Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

That's not exactly what we meant, but it's easy to fix:
maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42


oh man... glory glory hallellujah.... FINALYYYYYYYYYYYYY... that worked!!! thank you so much.. have one minor question:


all the time I've been working on this, when I print list of files they print thus:

1.jpg
2.jpg

etc...

now after I incorporated your code they print:

/Users/<me>/Documents/to_photoblog/2008-3/images/1.jpg
/Users/<me>/Documents/to_photoblog/2008-3/images/2.jpg
etc
just curious as to why...

(this is path to just test dir; path to real situation is:

/Users/<me>/apache-tomcat-5.5.31/webapps/photoblog/section9/page1/images etc...)
(so I move my file-renaming class to page2/images/ then to page3/images/ etc....;-) too funky?? ;-)


thank you very much....









maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42

oh brother.. now am back to orig problem that class REMOVES files..

now the 2nd sort line, namely:



REMOVES FILES!!

(I have to first rename all files temporarily to "a_1.jpg" etc..)

so after I do this I have to sort them a 2nd time.. the 2nd sort line removes files!!
(files were not removed if I comment out 2nd sort line.....:-( )

I cannot understand this...

code:
http://mayacove.com/dev/java/ren.txt

(screenshot: http://mayacove.com/dev/java/ren.jpg)

oh man.. I don't believe this.............. :-(

thank you..



maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42

I think I know what it is..

I have to create a 2nd comparator and change regex to include "a_" in file name....;-)

am trying... not too well-versed w/regex...


again thank you all very much.. I really appreciate yr help w/the comparator...


Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

I guarantee that Arrays.sort() is not removing files.

Also, I think you can avoid a second comparator, and even a second sort. I'm thinking once the files are sorted you won't have to worry about name collisions like you did when they were shuffled, so you don't even have to go through the step of renaming them with the "a_". Rob, what do you think? That's safe, right?

Or you could rewrite Rob's comparator to work with file names that start with "a_", and just do your sorting after the rename step. Or you use the Natural one I linked to, which will work even if the number is in the middle of the string.

So many options, huh?

By the way, I think the use of inner classes, which I consider an advanced topic, is probably making things more confusing for you then they need to be. You can use multiple top-level classes, even all in the same file as long as only one of them is public.

Something like:


maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42

oh man.. you're right -- if I don't shuffle don't need to do temp rename first....:-) greatly simplifies things because then I only need one sort....

(I need two classes, one for when need to shuffle (where I do need temp-rename first, but don't need to sort (since I'm shuffling files)...;-)

then another class for when need to sort (and of course no shuffle...;)

I could do everything in one class and pass param(s) to the class then put cond's inside.. but I would be more prone to make mistakes like that (pass wrong param, etc..) and also the code would be more complicated....;-)

ok.. I will further review everything and do more final testing over the weekend...

again, thank you very very much to you and to everyone else for all your help... it's greatly appreciated... have a great weekend..



Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

Greg Charles wrote:Also, I think you can avoid a second comparator, and even a second sort. I'm thinking once the files are sorted you won't have to worry about name collisions like you did when they were shuffled, so you don't even have to go through the step of renaming them with the "a_". Rob, what do you think? That's safe, right?

I think so, yes.
maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42

once again wanted to thank everyone for their help.. I still have a few questions/comments... (no problems, just questions about the code...;-)

in the one where I shuffle files
(http://mayacove.com/dev/java/rens.txt, http://mayacove.com/dev/java/rens.jpg)

Rob said:



now for the one where I shuffle I find I have to use directory.list (i.e., get file names, not file objs), because later when am using ArrayList for the shuffle, method ArrayList.add() throws error if try to add file objs instead of strings.. you can't add objects to ArrayList? I looked in docs (http://download.oracle.com/javase/1,5.0/docs/api/java/util/ArrayList.html) you can add "element" -- it looks like it takes objects.. yet this throws error:






so, again, for inserting elements into ArrayList I have to get fileNAMES not file objects.....

does this make sense?

thank you...





Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

Then use the File.getName() method. An alternative is to switch back to listFiles, but change the comparator slightly:
maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42
thank you for yr prompt response, Rob..

this is for the one where I shuffle (so no comparator, as am not sorting in this one..)

.getName() throws error:

rens.java:70: getName() in java.io.File cannot be applied to (<anonymous java.io.FilenameFilter>)
String[] _temp_newFilesNames = directory.getName(new FilenameFilter() {

so code is now:



just changed directory.list() to directory.getName()..... I think maybe getName() does not work with the FilenameFilter()???

thank you...



Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

Hi Maya,

Did you check out the Javadocs here: java.io.File ? You can see all the supported methods documented. You're right that getName() doesn't support a FilenameFilter parameter. That's because it just returns the name of the File (a directory is a type of File), not a list of names of the files the directory contains. The two methods that do return directory listings are listFiles() and list(), the first returning an array of File objects and the second returning a list of String file names. It's really easy to get a file name from a File object, and also easy to get a File object from a file name, but they're not the same thing.

For an ArrayList, you're right that you can store any kind of Object in it. Files, Strings, Widgets ... it makes no difference. However, newer versions of Java let you specify a particular type, and generates a compiler error if you violate that. So you can have ArrayList<String> list = new ArrayList<String>(). Then if you try to store a File in that list, the compiler will complain. Annoying? It can be. But you'll learn that it's much better when the compiler fails than when the running program does.
maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42

hi Greg,

yes but look @ this code:





I have: ArrayList<File>

and still if element I add to ArrayList is a file it throws error... it seems only way to add a file is to create file obj "on the fly" and pass it the name of the file.. I just don't get why can't add existing files....

it's not a major issue or anything, was just curious about this...

(so getName() shouldn't be used if you're trying to get a listing of file names, only for current file (in my case "directory") file name.. makes sense..)

once again thank you very much..


Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

Right, don't use getName() to get a directory listing, because that's just not what it does.

For the ArrayList<File>, are you saying there's an error on line 5, if it's not commented out? That could happen if _temp_newFiles is defined as an array of Objects. Like,

The compiler can't tell that the Object you index is actually a File, so it errors out. You can fix that with a cast, like which says, "Hey compiler, trust me on this one. That Object will be a File. I personally guarantee it!" If you're wrong, it will blow up at run time with a ClassCastException.

Another option is just to declare _temp_newFiles as an array of Files. Then you don't need a cast, and you won't be able to accidentally store a non-File Object in there.
maya brown
Ranch Hand

Joined: Feb 18, 2009
Posts: 42

yes, that line does throw an error if I got files instead of file names in line above....

& yes, yr casting suggestion worked of course....;-)

(I can't declare it as an array.. because this is the list I will be shuffling, it has to be an ArrayList.... is that what you meant?)

and speaking of which: have always wondered why this line



cannot be declared like this


b/c if I do like this (2nd option) I get this error when compile:

rens.java:101: incompatible types
found : java.lang.Object[]
required: java.io.File[][]
File[] Files_after_shuffle[] = listToShuffle.toArray();

(this is for AFTER the shuffle, I convert ArrayList into regular array... (wonder if I really need to do this? can you loop an ArrayList?)

thank you very much..


Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

You can't declare it (listToShuffle) as an array ... that's true ... but _temp_newFiles is an array, and I was suggesting you could declare it as a File array to avoid the cast.

ArrayList.toArray() returns an array of Objects, not an array of files. There is however another version of toArray() that will return an array of the proper type.



That last line is a bit weird, and I don't really like the syntax of it. If it's easier for you to read you can do it like this instead:




Finally, yes, you can iterate through an ArrayList. The easiest way is:

Rob Spoor
Sheriff

Joined: Oct 27, 2005
Posts: 19760
    
  20

Greg Charles wrote:

That last line is a bit weird, and I don't really like the syntax of it.

In this case it is a bit weird as it won't compile. It should be either "new File[0]" or "new File[] {}", both of which create an empty array.

This code is almost the same as the code you provided afterwards. The only difference is in the size of the array argument. When it's too small, reflection is used to create a new array of the exact same type which is then filled with the content of the collection. Otherwise, the original array is used. By supplying an empty array you will always get the reflection code (unless the collection is empty).
Because reflection is relatively slow I agree that using an array that's large enough from the start is better.
Greg Charles
Sheriff

Joined: Oct 01, 2001
Posts: 2861
    
  11

Oh, yep. I didn't mean to chunk that 0 in there. The performance isn't much of an issue though. I had to run the code in a loop 100,000 times for it to make a significant difference, and even then it was less than 1/30th of a second.



Reflection: 94
Instantiation: 62

So, just write it whichever way seems clearer.
 
 
subject: list files names a litle "counting" problem