views:

370

answers:

4

SOLVED:

This is what was wrong:

    current.addFolder(folder); (in the final else clause of the if statement)

Added a new folder, but did not guarantee that the folder passed is the folder added, it may simply do nothing if the folder already exists, so to overcome this I changed addFolder to return the actual folder (for example if it already existed) and I assigned folder to that return value. And that did the trick, so now I've got:

    folder = current.addFolder(folder);
    current = folder;

Thanks a lot people, your help was much appreciated :)


This is going to be a very long post, hopefully you can understand what I'm talking about and I appreciate any help. Thanks


Basically, I've created a personal, non-commercial project (which I don't plan to release) that can read ZIP and RAR files. It can only read the contents in the archive, the folders inside, the files inside the folders and its properties (such as last modified date, last modified time, CRC checksum, uncompressed size, compressed size and file name). It can't extract files either, so it's really a ZIP/RAR viewer if you may.

Anyway that's slightly irrelevant to my problem but I thought I'd give you some background info.

Now for my problem:

I can successfully list all the folders and files inside a ZIP archive, so now I want to take that raw input and link it together in some useful way. I made 2 classes: ArchiveFile (represents a file inside a ZIP) and ArchiveFolder (represents a folder inside a ZIP). They both have some useful methods such as getLastModifiedDate, getName, getPath and so on. But the difference is that ArchiveFolder can hold an ArrayList of ArchiveFile's and additional ArchiveFolder's (think of this as files and folders inside a folder).

Now I want to populate my raw input into one root ArchiveFolder, which will have all the files in the root dir of the ZIP in the ArchiveFile's ArrayList and any additional folders in the root dir of the ZIP in the ArchiveFolder's ArrayList (and this process can continue on like this like a chain reaction (more files/folders in that ArchiveFolder etc etc).

So I came up with the following code:

while (archive.hasMore()) {
    String path = ""; 
    ArchiveFolder current = root; 
    String[] contents = archive.getName().split("/");

    for (int x = 0; x < contents.length; ++x) {
        if (x == (contents.length - 1) && !archive.getName().endsWith("/")) { // If on last item and item is a file 
            path += contents[x]; // Update final path ArchiveFile 
            file = new ArchiveFile(path, contents[x], archive.getUncompressedSize(), archive.getCompressedSize(), archive.getModifiedTime(), archive.getModifiedDate(), archive.getCRC());

            current.addFile(file); // Create and add the file to the current ArchiveFolder
        }
        else if (x == (contents.length - 1)) { // Else if we are on last item and it is a folder
            path += contents[x] + "/"; // Update final path
            ArchiveFolder folder = new ArchiveFolder(path, contents[x], archive.getModifiedTime(), archive.getModifiedDate());

            current.addFolder(folder); // Create and add this folder to the current ArchiveFile
        }
        else { // Else if we are still traversing through the path
            path += contents[x] + "/"; // Update path
            ArchiveFolder folder = new ArchiveFolder(path, contents[x]);

            current.addFolder(folder); // Create and add folder (remember we do not know the modified date/time as all we know is the path, so we can deduce the name only)
            current = folder; // Update current ArchiveFolder to the newly created one for the next iteration of the for loop
        }
    }

    archive.getNext();
}

Assume that root is the root ArchiveFolder (initially empty). And that archive.getName() returns the name of the current file OR folder in the following fashion: file.txt or folder1/file2.txt or folder4/folder2/ (this is a empty folder) etc. So basically the relative path from the root of the ZIP archive.

Please read through the comments in the above code to familiarize yourself with it. Also assume that the addFolder method in an ArchiveFile, only adds the folder if it doesn't exist already (so there are no multiple folders) and it also updates the time and date of an existing folder if it is blank (ie it was a intermediate folder we only knew the name of, but now we know its details). The code for addFolder is (pretty self-explanitory):

public void addFolder(ArchiveFolder folder) {
    int loc = folders.indexOf(folder); // folders is the ArrayList containing ArchiveFolder's

    if (loc == -1) {
        folders.add(folder);
    }
    else {
        ArchiveFolder real = folders.get(loc);

        if (real.getTime() == null) {
            real.setTime(folder.getTime());
            real.setDate(folder.getDate());
        }
    }
}

So I can't see anything wrong with the code, it works and after finishing, the root ArchiveFolder contains all the files in the root of the ZIP as I want it to, and it contains all the direcories in the root folder as I want it to. So you'd think it works as expected, but no the ArchiveFolder's in the root folder don't contain the data inside those 'child' folders, it's just a blank folder with no additional files and folders (while it does really contain some more files/folders when viewed in WinZip).

After debugging using Eclipse, the for loop does iterate through all the files (even those not included above), so this led me to believe that there is a problem with this line of the code:

            current = folder;

What it does is, it updates the current folder (used as an intermediate by the loop) to the newly added folder.

I thought Java passed by reference and thus all new operations and new additions in future ArchiveFile's and ArchiveFolder's are automatically updated, and parent ArchiveFolder's will be updated accordingly. But that does not appear to be the case?

I know this is a long ass post and I really hope anyone can help me out with this.

Thanks in advance.

+1  A: 

Java does not actually pass references in the way you'd understand this in C++ for example. It passes by value, but all variables of non-primitive types are actually pointers to objects. So whenever you pass a variable to a method, you are giving or a copy of the pointer, meaning both variables point to the same object (change the object from one and the other will "see" the change. But assigning a different value to the pointer on caller or callee side will not change the other side's pointer.

Hope I'm clear?

Romain
I get what you mean and this is what I was afraid of. Looks like I need to find a new way of implementing my solution. All I really want is a bunch of:folder/folder/file2.txtfile1.txtfolder2/To convert into nice and neat little linked ArchiveFile's and ArchiveFolder's.
Sbm007
I don't think that's relevant, at least to the line he was looking at - both "current" and "folder" are local variables there.
Sbodd
-1 while it is a nice explanation, it does not affect the line mentioned as the reference is declared in the method and not passed in.
josefx
A: 

I suspect you haven't overloaded equals() and hashCode() correctly on your ArchiveFolder class, and thus

folders.indexOf(folder)

in addFolder() is always returning -1.

Sbodd
Sorry, I should've made that clear. I did overload them both. hashCode returns the hashCode of the path (String) and equals simply checks if both hashCodes are equal or not. I tested this out and it does work. So this is unfortunately not where the problem lies. Your help is much appreciated.
Sbm007
A: 

Hi Care to post code for

addFile 

?

ring bearer
I have found my problem, and I'm in the process of editing my post to explain what exactly was wrong. Anyhow it's: public void addFile(ArchiveFile file) { files.add(file); //files is the ArrayList for the files
Sbm007
+1  A: 

Since you use eclipse, set a breakpoint and step through the method, it may take time but it helps with finding bugs. (check the object ids for example to see if the reference has changed).

josefx
Thanks again. This helped me found the problem.
Sbm007