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

Posted

技术标签:

【中文标题】Java:如何“修剪”字节数组?【英文标题】:Java: How to "trim" a byte array? 【发布时间】:2010-12-27 12:06:49 【问题描述】:

所以我有一些代码可以从文件中读取一定数量的字节并返回结果字节数组(这基本上用于将文件分块以(最终)作为 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[],但它只有一半的数据。

【问题讨论】:

【参考方案1】:

您也可以使用文件的大小来计算剩余的字节数。

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;

这样您就不会创建额外的数组,也不需要副本。可能影响不大。 重要的一点IMO:检查read返回的值,我认为它可能小于剩余字节。 javadoc 声明:

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

【讨论】:

【参考方案2】:

您必须检查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;

【讨论】:

使用上面帖子中的 Arrays.copyOf 而不是 System.arraycopy (引发异常),这非常有效!谢谢! 已更正,我在比较中有错字,应该使用== 而不是= @Erin Drummond:System.arraycopy() 抛出的异常是什么? 这是一个 IndexOutOfBoundsException iirc @Erin Drummond:我明白为什么会发生这种情况并修正了我的答案。 System.arraycopy() 的最后一个参数应该是 bytesRead,而不是 chunkSize。呸!对于那个很抱歉。请尝试使用我更新的答案并确认它已修复。谢谢:)【参考方案3】:

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 pre-6,那么你需要自己实现Arrays.copyOf

byte[] r = new byte[read];
System.arraycopy(data, 0, r, 0, read);
return r;

【讨论】:

以上是关于Java:如何“修剪”字节数组?的主要内容,如果未能解决你的问题,请参考以下文章

java字节数组如何判断实际元素个数。

在java中如何把字节数组存储到数据库?

从 C# 中的字节数组中删除尾随空值

java和c#的字节数组转换问题

如何在Java中将二维布尔数组转换为一维字节数组?

如何在 Java 中初始化字节数组?