【问题标题】:OutOfMemoryError while break zip file into two parts将 zip 文件分成两部分时出现 OutOfMemoryError
【发布时间】:2014-12-08 08:13:17
【问题描述】:

我的应用程序将 .zip 文件分成两部分。当文件大小低于 100MB 时,它可以正常工作。如果文件大小超过 100MB,它会给出

java.lang.OutOfMemoryError
    at java.io.FileInputStream.readBytes(Native Method)
    at java.io.FileInputStream.read(FileInputStream.java:198)

我正在使用 glassfishV3 和 JDK6

-Xms512m -Xmx512m 不够用

then I have set 
<jvm-options>-Xms1024m</jvm-options>
<jvm-options>-Xmx1024m</jvm-options>

然后它给了

"Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine."

public void create() {
    byte[] bFile = takeByteArr("file1.zip");
    byte[] bPart1 = Arrays.copyOfRange(bFile, 0, 100000);
    byte[] bPart2 = Arrays.copyOfRange(bFile, 100000, bFile.length);
    createFile(bPart1, "part1.zip");
    createFile(bPart2, "part2.zip");
}

void createFile(byte[] bFile, String path) {
    try {
        FileOutputStream fos = new FileOutputStream(path);
        fos.write(bFile);
        fos.close();
    } catch (FileNotFoundException ex) {
        System.out.println("FileNotFoundException : " + ex);
    } catch (IOException ioe) {
        System.out.println("IOException : " + ioe);
    }
}

byte[] takeByteArr(String filePath) {
    File file = new File(filePath);
    byte[] bFile = new byte[(int) file.length()];
    try {
        FileInputStream  fileInputStream = new FileInputStream(file);
        fileInputStream.read(bFile);
        fileInputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return bFile;
}

【问题讨论】:

  • 您的计算机上有多少内存?当您收到此消息时,有多少可用 RAM?你有 32 位或 64 位系统和 JDK。当我收到此消息时,我会尝试关闭尽可能多的程序并重新启动,大多数情况下就足够了。
  • 真的必须用 Java 完成吗?也许可以从 Java 调用 OS 命令来拆分文件...
  • 为什么你要这样做?没有所有其他部分,这些部分就毫无意义。似乎是徒劳的。在任何情况下,如果您只是将前 100000 个字节复制到另一块内存中,然后假设其余部分也将适合内存以及原始文件,那么它肯定不会起作用。文件应一次处理一行或一条记录或一个缓冲区。
  • @StephaneM - 我的电脑 RAM 是 4GB 和 1.5GB 可用。它在 64 位 windows 7 操作系统和 JDK 64 位上运行。
  • @BorisPavlovic - 是的,我必须在 java 中完成。我正在 Windows 7 中开发此应用程序。但我必须在 centOs 中部署它。所以我认为使用 os 命令将无助于解决这个问题。

标签: glassfish-3 fileinputstream fileoutputstream java-6


【解决方案1】:

正如评论中已经建议的那样,大文件不会被读入一个部分,而是读入一个较小的缓冲区。然后处理缓冲区,在您的情况下,这会将部分文件保存到磁盘,并在逐块读取文件的循环中重复使用。这种方法的优点是您只需要与缓冲区大小一样多的内存。

FileInputStream 类有一个名为 read(byte[] b, int off, int len) 的方法,它从输入流。该方法返回一个 int,表示在方法调用期间读取的字节数,如果什么都无法读取,则返回 -1

例子:

    byte[] b = new byte[1024];
    int read = inputStream.read(b, 0, 1024);

现在您有一个字节数组 b,它有 1024 个字节大,包含 read 个字节的内容。

您可以循环浏览您的文件,但您必须注意最后一部分。字节数组缓冲区的大小也将是 100000,但我想您不想创建具有该大小的最后一部分。因此,您必须使用实际上是内容的最后一部分的字节数重新创建缓冲区。

您的代码可能如下所示:

public void create() throws IOException {
    FileInputStream in = new FileInputStream(new File("file1.zip"));

    byte[] b = new byte[100000];
    int read;
    int counter = 0;
    while ((read = in.read(b, 0, 100000)) != -1) {
        if(read != 100000) { // <- the last part
            b = Arrays.copyOfRange(b, 0, read);
        }
        createFile(b, "part" + counter++ + ".zip");
        b = new byte[100000];
    }  
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 2011-09-24
    • 2021-09-19
    • 2023-03-22
    • 2015-09-25
    • 1970-01-01
    相关资源
    最近更新 更多