Java:如何“修剪”字节数组?

7

我有一些代码,可以从文件中读取特定数量的字节并返回结果字节数组(这基本上用于将文件分块以发送到网络上,最终是base64编码的ASCII文本)。

它工作得很好,但是当生成文件的最后一个块时,它不是完整的块。因此,生成的字节数组不是完整的。但是,它是一个常量大小,这意味着当文件重新组合时,会在末尾附加一堆额外的数据(可能是0)。

如何使文件的最后一个块的byte[]只包含它需要的数据? 代码看起来像这样:

 private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    byte[] data = new byte[chunkSize];
    raf.read(data);        
    raf.close();
    return data;
}

如果chunkSize大于文件中剩余的字节数,则会返回一个完整大小的byte[],但其中只填充了一半的数据。

3个回答

6

您需要检查RandomAccessFile.read()的返回值以确定读取的字节数。如果与chunkSize不同,则必须将数组复制到较小的数组中并返回。

private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    byte[] data = new byte[chunkSize];
    int bytesRead = raf.read(data);
    if (bytesRead != chunkSize) {
         byte[] smallerData = new byte[bytesRead];
         System.arraycopy(data, 0, smallerData, 0, bytesRead);
         data = smallerData;
    }
    raf.close();
    return data;
}

1
使用上面帖子中的Arrays.copyOf而不是System.arraycopy(它抛出了异常),这个方法完美地解决了问题!谢谢! - Erin Drummond
更正,我在比较中打错了字,应该使用==而不是= - notnoop
@Erin Drummond:System.arraycopy() 抛出了什么异常? - Asaph
如果我没记错的话,这是一个IndexOutOfBoundsException。 - Erin Drummond
@Erin Drummond:我明白为什么会出现这种情况并修复了我的答案。System.arraycopy()的最后一个参数应该是bytesRead而不是chunkSize。呃!对此感到抱歉。请尝试使用我的更新答案并确认它已经修复了问题。谢谢 :) - Asaph

2

RandomAccessFile.read() 方法返回读取的字节数,所以您可以在需要时复制该数组:

private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    byte[] data = new byte[chunkSize];
    int read = raf.read(data);
    raf.close();
    if (read == data.length) return data;
    else
      return Arrays.copyOf(data, read);
}

如果您使用的是Java 6之前的版本,则需要自己实现Arrays.copyOf
byte[] r = new byte[read];
System.arraycopy(data, 0, r, 0, read);
return r;

0
您还可以使用文件大小来计算剩余字节数。
private byte[] readData(File f, int startByte, int chunkSize) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(f, "r");
    raf.seek(startByte);
    int size = (int) Math.min(chunkSize, raf.length()-startByte);
    byte[] data = new byte[size];
    raf.read(data);
    // TODO check the value returned by read (throw Exception or loop)
    raf.close();
    return data;
}

这样你就不需要创建额外的数组,也不需要复制。可能影响不大。
我认为一个重要的点是:检查read返回的值,我认为它可能小于剩余的字节数。Javadoc说明如下:

读取的字节数最多等于b的长度


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接