读取file到byte []数组时的java.lang.OutOfMemoryError

时间:2013-01-30 07:38:25

标签: java arrays io out-of-memory

是否有更清洁,更快捷的方法:

BufferedReader inputReader = new BufferedReader(new InputStreamReader(context.openFileInput("data.txt")));
String inputString;
StringBuilder stringBuffer = new StringBuilder();
while ((inputString = inputReader.readLine()) != null) {
    stringBuffer.append(inputString + "\n");
}
text = stringBuffer.toString();
byte[] data = text.getBytes();

基本上我正在尝试将文件转换为byte[],除非文件足够大,否则会遇到outofmemory错误。我一直在寻找SO的解决方案,我试图在这里做到这一点,但它没有用。任何帮助将不胜感激。

7 个答案:

答案 0 :(得分:6)

很少有建议:

  1. 您无需创建字符串构建器。您可以直接从文件中读取字节。
  2. 如果您读取多个文件,请检查内存中剩余的byte []数组,即使不需要也是如此。
  3. 最后使用-Xmx选项增加java进程的最大内存。

答案 1 :(得分:3)

我们知道这个文件的大小,通过直接分配给定大小的字节数组而不是扩展它,可以节省一半的内存:

byte [] data = new byte[ (int) file.length() ];
FileInputStream fin = new FileInputStream(file);
int n = 0;
while ( (n = fin.read(data, n, data.length() - n) ) > 0);

这将避免分配不必要的额外结构。字节数组只分配一次,从头开始具有正确的大小。 while循环确保加载所有数据(read(byte[], offset, length)可能只读取文件的一部分但返回读取的字节数。)

澄清:当StringBuilder用完时,它会分配一个比初始缓冲区大两倍的新缓冲区。此时,我们使用的内存量大约是最低要求的两倍。在最简并的情况下(最后一个字节不适合某些已经很大的缓冲区),可能需要接近最小RAM量的三倍。

答案 2 :(得分:2)

如果没有足够的内存来存储整个文件,您可以尝试重新考虑算法,以便在读取时处理文件数据,而无需构建大型byte[]数组数据。

如果您已经尝试通过使用java参数来增加-Xmx内存,则没有任何解决方案,这将允许您将数据存储在内存中,因为无法将数据存储在那里它的大小。

答案 3 :(得分:0)

您正在将字节复制到char(使用两倍的空间)并再次返回字节。

InputStream in = context.openFileInput("data.txt");
ByteArrayOutputStream bais = new ByteArrayOutputStream();
byte[] bytes = new byte[8192];
for(int len; (lne = in.read(bytes) > 0;)
   bais.write(bytes, 0, len);
in.close();
return bais.toByteArray();

这将是你的内存需求的一半,但它仍然意味着你的内存不足。在这种情况下,您必须

  • 增加最大堆大小
  • 逐步处理文件,而不是一次处理所有文件
  • 使用内存映射文件,允许您在不使用太多堆的情况下“加载”文件。

答案 4 :(得分:0)

这类似于File to byte[] in Java

您当前正在读取字节数,将它们转换为字符,然后尝试将它们转换回字节。来自Java API中的InputStreamReader类:

  

InputStreamReader是从字节流到字符流的桥接器:它读取字节并将它们解码为字符..

以字节为单位读取会更有效率。

一种方法是直接在ByteArrayInputStream或Jakarta Commons context.openFileInput()上使用IOUtils.toByteArray(InputStream),或者如果您使用的是JDK7,则可以使用Files.readAllBytes(Path)。< / p>

答案 5 :(得分:0)

“更清洁,更快捷的方式”根本不是这样做的。它不会扩展。一次处理一个文件。

答案 6 :(得分:-1)

此解决方案将在加载前测试可用内存...

File test = new File("c:/tmp/example.txt");

    long freeMemory = Runtime.getRuntime().freeMemory();
    if(test.length()<freeMemory) {
        byte[] bytes = new byte[(int) test.length()];
        FileChannel fc = new FileInputStream(test).getChannel();
        MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int) fc.size());

        while(mbb.hasRemaining()) {
            mbb.get(bytes);
        }
        fc.close();
    }