【问题标题】:How to store each file in a zip archive, in an array using Java?如何使用 Java 将每个文件存储在 zip 存档中的数组中?
【发布时间】:2013-04-02 16:37:22
【问题描述】:

理想情况下,我只想读取 zip 存档并将每个文件存储在准备编译的 Iterable 中。 (假设 zip 仅包含 .java 文件)

这样会很好,但这不起作用,因为我无法获取 zip 中每个文件的路径。

private ArrayList<String> javaFilePaths = new ArrayList<String>();
Iterable<? extends JavaFileObject> = fileManager.getJavaFileObjectsFromStrings(javaFilePaths);

是否可以让ArrayList 的每个元素成为存档中文件的路径?到目前为止,我只能通过 zip 存档并获取所有无用的文件名,因为当我调用 getJavaFileObjectsFromStrings(javaFilePaths); 时,它不会是文件的完整路径。也许我需要先将每个文件的内容存储在一个新的JavaFileObject 中?真的不确定解决这个问题的最佳方法......

有人可以帮忙解决这个问题吗,事实证明这很棘手!

UPDATE:

考虑将 zip 存档中的每个文件作为 File 对象存储在 File 类型的数组中

然后调用getJavaFileObjectsFromFiles(arrayOfFiles);方法。

解决方案、想法?

【问题讨论】:

  • 不确定您要做什么,但请查看java.util.zip.ZipInputStream
  • @orid 我“认为”我需要遍历 zip 文件并将每个 .java 文件作为 File 对象存储在 File 类型的数组/列表中
  • 你不应该“思考”。你应该知道你需要什么以及你想问什么
  • 您不能将 ZipEntry 存储为 .java 文件,因为这些文件可能包含字节码,除非您确定它是包含一些工件源的 JarInputStream
  • @A.J 抱歉,我不是 Java 专家,我也不是什么都懂。这就是为什么我来到这里有很多经验的地方。我知道一般概念,但我不知道如何以编程方式进行。主要概念是用户浏览包含 Java 文件的 zip 存档,然后将 Java 文件临时存储在内存中,然后编译生成类文件。除了如何将 zip 文件夹中的文件存储到数组中之外,我一切正常。

标签: java arrays compiler-construction zip archive


【解决方案1】:

我会按照您的要求对您的回答发表评论,但 cmets 的长度有限。 可以实现您想要的:编译源代码而无需将其实际提取到文件系统上的物理文件中。

引用接口StandardJavaFileManager的API

此文件管理器创建代表常规文件、压缩文件条目或类似文件系统的基于容器中的条目的文件对象

在谷歌搜索我发现了以下文章:Create dynamic applications with javax.tools

在“Java 编译:概念和实现”部分中,它在“源文件”中声明了以下内容:

要编译的一个或多个 .java 源文件。 JavaFileManager 提供了一个抽象文件系统,它将源文件名和输出文件名映射到 JavaFileObject 实例。 (这里的文件是指一个唯一名称和一个字节序列之间的关联。客户端不需要使用实际的文件系统。)

以下文章也是如此:Dynamic in-memory compilation

两者都使用 CharSequence 作为编译源。 您可以尝试根据上面文章中的解释构建自己的实现,并更改为基于 ZipEntry。否则,您可以将 zip 条目的内容(正如您所提到的,您知道它是一个 java 源文件)到 StringBuffer 中,然后使用其中一篇文章中的实现来编译它。

【讨论】:

    【解决方案2】:

    您可以扫描 ZIP 文件并保留对其条目的引用。然后从列表中选择条目,提取文件并执行您需要执行的任何操作。最初不必完全读取所有文件。一个缺点:在处理完 ZIP 存档之前,您不得致电 ZipFile.close()。

    例如:

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.nio.charset.Charset;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Enumeration;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipException;
    import java.util.zip.ZipFile;
    
    public class SO {
        static class ZipFileRecord {
            final ZipFile zf;
            final ZipEntry ze;
    
            public ZipFileRecord(ZipFile zf, ZipEntry ze) {
                super();
                this.zf = zf;
                this.ze = ze;
            }
    
            public String content() throws IOException {
                InputStream is = zf.getInputStream(ze);
                BufferedReader br = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
                StringBuilder sb = new StringBuilder();
                String line = null;
                int count = 5;  // limit loop for reduced output
                while ((line = br.readLine())!=null) {
                    sb.append(line);
                    sb.append("\n");
                    if (count--<=0) {
                        sb.append("...\n");
                        break;
                    }
                }
                br.close();
                return sb.toString();
            }
        }
        public static class ZipWalker {
            final ArrayList<ZipFileRecord> list = new ArrayList<>();
            ZipFile zf;
    
            public void scan(String fn) throws ZipException, IOException {
                File f = new File(fn);
                if (!f.exists()) throw new RuntimeException("File not found: " + f);
                zf = new ZipFile(f);
                Enumeration<? extends ZipEntry> entries = zf.entries();
                for (ZipEntry ze : Collections.list(entries)) {
                    if (ze.getName().endsWith(".java")) {
                        list.add(new ZipFileRecord(zf, ze));
                    }
                }
            }
    
            public void dump() throws IOException {
                int count = 3;  // limit loop for reduced output
                for (ZipFileRecord fr : list) {
                    System.out.println("=============> " + fr.ze);
                    System.out.println(fr.content());
                    if (count--<=0)
                        break;
                }
                zf.close();
            }
        }
        public static void main(String[] args) throws ZipException, IOException {
            ZipWalker zw = new ZipWalker();
            zw.scan("path/to/your/file.zip");
            zw.dump();
        }
    }
    

    值得注意的事情:

    1. scan 方法执行扫描,dump 方法代表您想要对文件执行的所有其他操作。
    2. 完成 ZIP 文件后,必须调用 ZipFile.close()。如果已调用 close(),则无法从其条目中读取数据。
    3. 代码中的 count 变量是为了简化输出 - 您需要删除这些变量以及相关的 ifs。
    4. 为简单起见,我使用了Reader 和UTF-8。如果您将文件内容呈现给用户,您可能必须处理文件的字符集。您可能还必须处理它以进行编译。

    【讨论】:

    • 请看我的回答,如果您有任何想法,请告知? :)
    【解决方案3】:

    我快到了,它可以工作,但是 FileOutputStream 创建文件,我可以在之后简单地删除它,但是有没有办法在不创建文件的情况下做到这一点,而是让它成为虚拟的?请评论我的回答。

    btnBrowse.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    int returnVal = fileChooser.showOpenDialog(null);
                    if (returnVal == JFileChooser.APPROVE_OPTION) {
                        try {
                            isZip = true;
                            ZipFile zipFile = new ZipFile(fileChooser.getSelectedFile());
                            Enumeration<?> enu = zipFile.entries();
                            while (enu.hasMoreElements()) {
                                ZipEntry zipEntry = (ZipEntry) enu.nextElement();
                                File file = new File(zipEntry.getName());
                                InputStream is = zipFile.getInputStream(zipEntry);
                                FileOutputStream fos = new FileOutputStream(file);
                                byte[] bytes = new byte[1024];
                                int length;
                                while ((length = is.read(bytes)) >= 0) {
                                    fos.write(bytes, 0, length);
                                }
                                is.close();
                                fos.close();
                                fileArrayList.add(file);
                            }
                            zipFile.close();
                        } catch (IOException ioe) {
                            ioe.printStackTrace();
                        }
                    }
                }
            });
    

    【讨论】:

    • 我想我开始明白你需要什么了。现在我正在处理我的主要项目(支付账单的项目),但明天我将在这个主题上花费一些“stackoverflow 时间”。我想,这主要是关于“将 ZIP 虚拟化为一个数组”。可能您需要更多关于将它与 JavaCompiler 和朋友连接起来的详细信息?
    • @RainerSchwarze 实际上我已经成功地从 JTextArea 编译了它,现在我正在添加下一个功能,即浏览包含要编译的多个 Java 源文件的 zip :) 我很享受这个项目很多,因为它挑战了我的知识(计算机科学一年级学生)。
    猜你喜欢
    • 1970-01-01
    • 2017-12-15
    • 2013-05-09
    • 1970-01-01
    • 2018-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    相关资源
    最近更新 更多