【发布时间】:2011-01-31 10:12:23
【问题描述】:
已解决:
这是错的:
current.addFolder(folder); (in the final else clause of the if statement)
添加了一个新文件夹,但不保证传递的文件夹是添加的文件夹,如果文件夹已经存在,它可能什么都不做,所以为了克服这个问题,我更改了 addFolder 以返回实际文件夹(例如,如果它已经存在),我将文件夹分配给该返回值。这样就成功了,所以现在我得到了:
folder = current.addFolder(folder);
current = folder;
非常感谢大家,非常感谢您的帮助 :)
这将是一篇很长的文章,希望你能理解我在说什么,我感谢任何帮助。谢谢
基本上,我创建了一个可以读取 ZIP 和 RAR 文件的个人非商业项目(我不打算发布)。它只能读取存档中的内容、里面的文件夹、文件夹里面的文件及其属性(如上次修改日期、上次修改时间、CRC校验和、未压缩大小、压缩大小和文件名)。它也不能提取文件,所以如果可以的话,它确实是一个 ZIP/RAR 查看器。
无论如何,这与我的问题有点无关,但我想我会给你一些背景信息。
现在解决我的问题:
我可以成功列出 ZIP 存档中的所有文件夹和文件,所以现在我想获取原始输入并以某种有用的方式将它们链接在一起。我做了 2 个类:ArchiveFile(代表 ZIP 中的文件)和 ArchiveFolder(代表 ZIP 中的文件夹)。它们都有一些有用的方法,例如 getLastModifiedDate、getName、getPath 等。 但不同之处在于 ArchiveFolder 可以保存 ArchiveFile 和其他 ArchiveFolder 的 ArrayList (将其视为文件夹中的文件和文件夹)。
现在我想将原始输入填充到一个 root ArchiveFolder 中,该文件夹将包含 ArchiveFile 的 ArrayList 中 ZIP 根目录中的所有文件以及根目录中的任何其他文件夹ArchiveFolder 的 ArrayList 中的 ZIP(并且此过程可以像连锁反应一样继续进行(该 ArchiveFolder 中的更多文件/文件夹等)。
所以我想出了以下代码:
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();
}
假设 root 是根 ArchiveFolder(最初为空)。 并且 archive.getName() 以下列方式返回当前文件或文件夹的名称:file.txt 或 folder1/file2.txt 或 folder4/folder2/ (这是一个空文件夹)等。所以基本上是相对路径ZIP 存档的根目录。
请通读上述代码中的 cmets 以熟悉它。还假设 ArchiveFile 中的 addFolder 方法仅在文件夹不存在时添加文件夹(因此没有多个文件夹),并且如果现有文件夹为空白(即它是中间文件夹我们只知道它的名称,但现在我们知道它的详细信息)。 addFolder 的代码是(不言自明):
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());
}
}
}
所以我看不出代码有什么问题,它可以工作,完成后,根 ArchiveFolder 包含我想要的 ZIP 根目录中的所有文件,它包含根文件夹中的所有目录如我所愿。所以你会认为它按预期工作,但是根文件夹中的 ArchiveFolder 不包含那些“子”文件夹中的数据,它只是一个没有其他文件和文件夹的空白文件夹(虽然它确实包含更多在 WinZip 中查看的文件/文件夹)。
使用 Eclipse 调试后,for 循环确实会遍历所有文件(甚至包括上面未包含的文件),所以这让我相信这行代码有问题:
current = folder;
它的作用是将当前文件夹(用作循环的中间)更新到新添加的文件夹。
我认为 Java 是通过引用传递的,因此将来 ArchiveFile 和 ArchiveFolder 中的所有新操作和新增内容都会自动更新,并且父 ArchiveFolder 将相应更新。但好像不是这样的?
我知道这是一个很长的帖子,我真的希望有人能帮我解决这个问题。
提前致谢。
【问题讨论】:
-
出于好奇,这些是基于
ZipInputStream/ZipOutputStream/ZipEntry/ZipFile类集吗? -
不,他们不是,这就是重点。我创建了一个 StandardByte 和 StandardFile,它们逐字节读取每个文件(使用 FileInputStream)并为我提供有用的方法(例如 searchBytes、getBytesAt 等)。我使用了公开可用的 ZIP 文件规范来实现读取支持。但是 RAR 是一种封闭格式,因此没有文件规范。是可用的,但我最终通过一个十六进制编辑器和大量的耐心+观察设法到达那里!
-
由于你使用eclipse,设置断点并逐步执行该方法,这可能需要一些时间,但它有助于发现错误。 (例如检查对象 id 以查看引用是否已更改)
-
天哪。是的,谢谢!!我发现了问题,我将编辑我的帖子并解释究竟是什么原因。请将您的建议作为回复发布,以便我接受 + 点赞。
-
@josefx:前几天处理存储在会话中的对象时,我刚刚被类似的事情所困扰。我将局部变量指向新实例,忘记了会话中的变量将是旧的。
标签: java object arraylist pass-by-reference