9

有没有更清洁和更快的方法来做到这一点:

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[],除非文件足够大,否则我会遇到内存不足错误。我一直在寻找解决方案,我在这里尝试这样做,但没有奏效。任何帮助,将不胜感激。

4

7 回答 7

6

几点建议:

  1. 您不需要创建字符串生成器。您可以直接从文件中读取字节。
  2. 如果您读取多个文件,即使不需要,也要检查内存中剩余的那些 byte[] 数组。
  3. 最后使用 -Xmx 选项增加 Java 进程的最大内存。
于 2013-01-30T07:45:11.230 回答
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 量的三倍。

于 2013-01-30T07:47:13.127 回答
2

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

如果你已经尝试过java通过参数来增加内存-Xmx,那么没有任何解决方案可以让你将数据存储在内存中,由于内存太大,内存无法定位。

于 2013-01-30T07:43:59.363 回答
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();

这将使您的内存需求减半,但仍可能意味着您的内存不足。在这种情况下,您必须

  • 增加最大堆大小
  • 逐步处理文件,而不是一次全部处理
  • 使用内存映射文件,它允许您在不使用太多堆的情况下“加载”文件。
于 2013-01-30T07:49:38.093 回答
0

这类似于Java 中的 File to byte[]

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

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

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

一种方法是ByteArrayInputStream直接使用 .oncontext.openFileInput()或 Jakarta Commons IOUtils.toByteArray(InputStream),或者如果您使用的是 JDK7,则可以使用Files.readAllBytes(Path).

于 2013-01-30T07:51:45.797 回答
-1

“更清洁和更快的方法”是根本不这样做。它没有规模。一次处理一个文件。

于 2013-01-30T11:36:16.523 回答
-2

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

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();
    }
于 2013-01-30T07:55:28.877 回答