【问题标题】:Java Reading large files into byte array chunk by chunkJava逐块将大文件读入字节数组
【发布时间】:2016-09-08 20:10:44
【问题描述】:

所以我一直在尝试制作一个将文件输入字节数组的小程序,然后它将该字节数组转换为十六进制,然后是二进制。然后它将使用二进制值(我还没想到当我到达这个阶段时要做什么),然后将其保存为自定义文件。

我研究了很多互联网代码,我可以将文件转换为字节数组和十六进制,但问题是我无法将大文件转换为字节数组(内存不足)。

这是不是完全失败的代码

public void rundis(Path pp) {
    byte bb[] = null;

    try {
        bb = Files.readAllBytes(pp); //Files.toByteArray(pathhold);
        System.out.println("byte array made");
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (bb.length != 0 || bb != null) {
        System.out.println("byte array filled");
        //send to method to turn into hex
    } else {
        System.out.println("byte array NOT filled");
    }

}

我知道流程应该如何进行,但我不知道如何正确编码。

有兴趣的流程:

  • 使用File输入文件
  • 逐块读取文件到字节数组中。前任。每个字节数组记录包含 600 个字节
  • 发送该块以转换为十六进制值 --> Integer.tohexstring
  • 发送该十六进制值块以制成二进制值 --> Integer.toBinarystring
  • 搞乱二进制值
  • 逐行保存到自定义文件

问题:: 我不知道如何将一个巨大的文件逐块转换为字节数组进行处理。 任何和所有的帮助将不胜感激,感谢您的阅读:)

【问题讨论】:

  • 文件有多大?
  • 大约 7GB
  • FileInputStream#read(byte[] b)。然后你可以指定一次读取多少字节。
  • 如果我问的不是太多,你能举一些例子吗?甚至是一个示例的链接,我阅读了它,但我不确定如何准确地实现它。 :)

标签: java


【解决方案1】:

要分块您的输入,请使用 FileInputStream:

    Path pp = FileSystems.getDefault().getPath("logs", "access.log");
    final int BUFFER_SIZE = 1024*1024; //this is actually bytes

    FileInputStream fis = new FileInputStream(pp.toFile());
    byte[] buffer = new byte[BUFFER_SIZE]; 
    int read = 0;
    while( ( read = fis.read( buffer ) ) > 0 ){
        // call your other methodes here...
    }

    fis.close();

【讨论】:

  • 别提了。 ;)
【解决方案2】:

要流式传输文件,您需要远离Files.readAllBytes()。对于小文件,它是一个不错的实用程序,但正如您所注意到的,对于大文件来说,它就没有那么多了。

在伪代码中它看起来像这样:

while there are more bytes available
    read some bytes
    process those bytes
    (write the result back to a file, if needed)

在 Java 中,您可以使用 FileInputStream 来读取文件 byte by bytechunk by chunk。假设我们想写回我们处理过的字节。首先我们打开文件:

FileInputStream is = new FileInputStream(new File("input.txt"));
FileOutputStream os = new FileOutputStream(new File("output.txt"));

我们需要FileOutputStream 来写回我们的结果 - 我们不想只是丢弃我们宝贵的处理数据,对吧?接下来我们需要一个保存一大块字节的缓冲区:

byte[] buf = new byte[4096];

多少字节由你决定,我有点喜欢 4096 字节的块。然后我们需要实际读取一些字节

int read = is.read(buf);

这将最多读取buf.length 字节并将它们存储在buf 中。它将返回读取的总字节数。然后我们处理字节:

//Assuming the processing function looks like this:
//byte[] process(byte[] data, int bytes);
byte[] ret = process(buf, read);

以上示例中的process() 是您的处理方法。它接受一个字节数组,它应该处理的字节数并将结果作为字节数组返回。

最后,我们将结果写回文件:

os.write(ret);

我们必须循环执行,直到文件中没有字节,所以我们为它写一个循环:

int read = 0;
while((read = is.read(buf)) > 0) {
    byte[] ret = process(buf, read);
    os.write(ret);
}

最后关闭流

is.close();
os.close();

就是这样。我们以 4096 字节的块处理文件并将结果写回文件。由你决定如何处理结果,你也可以通过 TCP 发送它,如果不需要它甚至丢弃它,或者甚至从 TCP 而不是文件 read,基本逻辑是相同的.

这仍然需要一些适当的错误处理来解决丢失的文件或错误的权限,但这取决于你来实现。


流程方法的示例实现:

//returns the hex-representation of the bytes
public static byte[] process(byte[] bytes, int length) {
    final char[] hexchars = "0123456789ABCDEF".toCharArray();
    char[] ret = new char[length * 2];
    for ( int i = 0; i < length; ++i) {
        int b = bytes[i] & 0xFF;
        ret[i * 2] = hexchars[b >>> 4];
        ret[i * 2 + 1] = hexchars[b & 0x0F];
    }
    return ret;
}

【讨论】:

  • 感谢详细的解释 man :) 但是你能解释一下“process(buf, read)”那部分吗?流程到底是什么?
  • 这是你的处理函数,它对字节“做某事”。我添加了一个示例实现,它返回字节的十六进制表示。
  • 这是愚蠢的,所以帮助您自担风险:) 我尝试将我从缓冲区数组中获得的值分配给另一个数组,它没有工作。感谢您竭尽全力帮助人 :) 编辑 不要帮我解决我之前提到的愚蠢的事情,我想办法解决
  • 你能具体说明我如何返回字节[]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多