【问题标题】:java: read large binary filejava:读取大型二进制文件
【发布时间】:2014-12-19 04:29:13
【问题描述】:

我需要读出一个包含 500000001 个二进制文件的给定大文件。之后我必须将它们翻译成 ASCII。

我的问题是在尝试将二进制文件存储在一个大数组中时发生的。我在数组 ioBuf 的定义处收到警告:

“int 类型的文字 16000000032 超出范围。”

我不知道如何保存这些数字以使用它们!有人有想法吗?

这是我的代码:

public byte[] read(){
    try{
        BufferedInputStream in = new BufferedInputStream(new FileInputStream("data.dat"));
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        BufferedOutputStream out = new BufferedOutputStream(bs);
        byte[] ioBuf = new byte[16000000032];       
        int bytesRead;
        while ((bytesRead = in.read(ioBuf)) != -1){
            out.write(ioBuf, 0, bytesRead);
        }
          out.close();
          in.close();
          return bs.toByteArray();
}

【问题讨论】:

  • 你可以尝试分块读取,然后处理。另一种选择是通过文件流式传输。
  • "500000001 二进制文件" 没有意义。你到底什么意思?为什么你试图一次将整个事情读入内存? “将它们翻译成 ASCII”是什么意思?
  • 嗨!感谢您的回答!阅读我解决的第一个二进制文件(请参阅下面的答案)。现在我正在努力实现您的想法(分块阅读)!

标签: java byte binaries large-data


【解决方案1】:

我从零开始取得了一些进步!但是我还是有问题。

我的想法是读取前 32 个字节,将它们转换为 int 数。然后是接下来的 32 个字节等。不幸的是,我只是得到第一个,不知道如何继续。

我发现了以下将这些数字转换为 int 的方法:

public static int byteArrayToInt(byte[] b){
    final ByteBuffer bb = ByteBuffer.wrap(b);
    bb.order(ByteOrder.LITTLE_ENDIAN);
    return bb.getInt();
}

所以现在我有:

    BufferedInputStream in=null;
    byte[] buf = new byte[32];
    try {
        in = new BufferedInputStream(new FileInputStream("ndata.dat"));
        in.read(buf);
        System.out.println(byteArrayToInt(buf));
        in.close();
    } catch (IOException e) {
        System.out.println("error while reading ndata.dat file");
    }

【讨论】:

  • 32bytes 多于一个 int?一个 int 是 4byte
  • 哦,是的!你说的对!这就是为什么输出包含多个数字:123456789
  • 好的!我已经阅读了这一点。我的文件包含很多数字,它们是二进制存储为小端 32 位整数。所以我的第一个 int 数是 123456789,它由 32 位或分别由 8 个字节组成。 :-)
【解决方案2】:

数组的最大索引是Integer.MAX_VALUE 并且16000000032 大于Integer.MAX_VALUE

Integer.MAX_VALUE = 2^31-1 = 2147483647

2147483647 < 16000000032

您可以通过检查数组是否已满并创建另一个并继续阅读来克服这个问题。 但我不太确定您的方法是否是执行此操作的最佳方法。 byte[Integer_MAX_VALUE] 很大;) 也许您可以将输入文件拆分成更小的块来处理它们。

编辑:这是您可以读取文件的单个 int 的方式。您可以将缓冲区的大小调整为要读取的数据量。但是您试图一次读取整个文件。

//Allocate buffer with 4byte = 32bit = Integer.SIZE
byte[] ioBuf = new byte[4];       
int bytesRead;
while ((bytesRead = in.read(ioBuf)) != -1){
   //if bytesRead == 4 you read 1 int
   //do your stuff
}

【讨论】:

  • 感谢您的快速答复!我可能计算错了。我的数据包含 500000001 个数字,二进制存储为有符号 little endian 32 位整数。
  • 那么你有 500000001 乘以 4byte ;) 数据格式化了吗?
  • 嗨!其实我不知道。第一次使用存储介质时,格式化不是应该做的事吗?
【解决方案3】:
  1. 如果您需要声明一个大常量,请在其上附加一个“L”,它向编译器表明这是一个long 常量。但是,正如另一个答案中提到的,您不能声明那么大的数组。
  2. 我怀疑本练习的目的是学习如何使用 java.nio.Buffer 系列类。

【讨论】:

  • 谢谢!我想你是对的!我真的学到了一些关于这个缓冲区的东西!
猜你喜欢
  • 1970-01-01
  • 2014-04-27
  • 1970-01-01
  • 2016-09-20
  • 2021-07-26
  • 2011-07-25
  • 1970-01-01
  • 1970-01-01
  • 2013-12-06
相关资源
最近更新 更多