使用 Java 读取/写入二进制数据的精妙之处

Subtleties in Reading/ Writing Binary Data with Java

我注意到 Java 使用字节数组缓冲区读取文件的一个现象,就像 C 的 fread() 一样,如果我不动态控制最终读取的长度,并且正在读取的数据的总大小不是缓冲区大小的倍数,那么多余的垃圾数据可能会被读入文件。执行二进制 I/O 时,一些复制的文件会呈现 有些 损坏。

垃圾值可能是以前存储在缓冲区中但未被覆盖的值,因为最终读取的缓冲区长度不完整。 在查看各种教程时,所有读取二进制数据的方法都类似于以下代码:

InputStream inputStream = new FileInputStream("prev_font.ttf");;
OutputStream outputStream = new FileOutputStream("font.ttf");
byte buffer[] = new byte[512];
while((read = inputStream.read(buffer)) != -1)
{
    outputStream.write(buffer, 0, read);
}
outputStream.close();
inputStream.close();

但是在从一个打包在 JAR 中的文件的输入流中读取时,我无法正确地复制该文件。我会输出为该类型的无效文件。

由于我对 JAR 访问还很陌生,所以我无法确定问题是出在我的资源文件路径还是其他方面。所以花了很多时间才意识到发生了什么。 我遇到的所有代码都有一个重要的缺失部分。读取的数量不应该是整个缓冲区,而只是读取的数量:

InputStream inputStream = new FileInputStream("prev_font.ttf");
OutputStream outputStream = new FileOutputStream(font.ttf");
byte dataBuffer[] = new byte[512];
int read;
while((read = inputStream.read(dataBuffer)) != -1)
{
    outputStream.write(dataBuffer, 0, read);
}
outputStream.close();
inputStream.close();

现在已经很好了,但是为什么在任何教程中都没有提到如此重要的内容?我只是看了不好的教程,还是 Java 应该处理溢出读取而我的实现不知何故关闭了?简直是出乎意料。

如果我的任何陈述有误,请纠正我,如果有任何问题,请提供替代解决方案来处理问题。

您提供的代码块之间没有太大区别,只是有一些小错别字,这意味着它们无法编译。缓冲区不会被读取损坏,但如果没有为循环的每次迭代提供读取的字节数,则输出文件会损坏。

要复制文件 - 例如 src -> dst 只需使用 try with resources 和内置 transferTo:

Path src = Path.of("prev_font.ttf");
Path dst = Path.of("font.ttf");
try(InputStream in  = Files.newInputStream(src);
   OutputStream out = Files.newOutputStream(dst)) {
    in.transferTo(out);
}

或调用 Files 的内置方法之一:

Files.copy(src, dst);
// or
Files.copy(src, dst, StandardCopyOption.REPLACE_EXISTING);