Java 读取二进制文件, 打包前执行和打包后执行读出来的 size 不一样?

2022-01-05 17:44:37 +08:00
 asanelder

读取代码如下

InputStream in = new ClassPathResource("binary_file.dat").getInputStream();
out = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while(in.read(b) != -1){
    out.write(b);
}

log.info("data size = {}", out.size());

俺使用两种方式执行

  1. 打包前执行
  2. 打包成 jar 包执行

发现两种方式的 size 不一样.

文件大小在 28M 左右.

奇怪啊~~~

797 次点击
所在节点    问与答
11 条回复
asanelder
2022-01-05 17:57:25 +08:00
神奇啊, 使用 guava 中的工具类来读取就没这个问题了...

in = new ClassPathResource("binary_file.dat").getInputStream();
data = ByteStreams.toByteArray(in);
log.info("data size = {}", out.size());
AoEiuV020CN
2022-01-05 18:05:29 +08:00
首先,代码有误,read 会返回长度 length ,write 时应当只 write 一个范围 0, length ,
asanelder
2022-01-05 18:17:17 +08:00
@AoEiuV020CN #2 就算有误的话, 相同的代码, 相同的文件, 一个是打包后执行, 一个是打包前执行, 按道理说, 应该结果也是一样的吧
AoEiuV020CN
2022-01-05 18:25:07 +08:00
@asanelder #3 具体原因我不知道,read 方法很容易涉及到框架内部或者 jvm 内部,要说直接运行和打包后运行保证这些内部环境完全一样我看也不能保证,没准当时内存占用多了一比特就导致不同的缓存处理进而导致其他其他不同,
不是很想深究错误的代码为什么会引发另一个错误,
codehz
2022-01-05 18:46:58 +08:00
@asanelder 打包之后被压缩了啊,然后就需要边解压边读取,zip 压缩也不是固定输出大小的压缩,解压的时候也很难预测要读多少内容才能得到 1024 ,通常的思路就是读固定大小,然后解出多少就提供多少(
Jwyt
2022-01-05 19:05:50 +08:00
@codehz 楼主说的是打 jar 包,不是被读的文件


不过代码确实有问题,应该是
(len=in.read(b)) !=-1;
out.write(b,0,len);
当然为啥会不一样我也不清楚,楼主可以把代码改了之后再打包试试
AoEiuV020CN
2022-01-05 19:26:41 +08:00
@Jwyt #6 应该就是打包压缩的问题,楼主代码中的 ClassPathResource 读取的文件是会被打包到 jar 里的,
边解压边读取导致无法指定读取 1024 字节,可能比如一次解压出了 500 个字节,read 就直接返回 500 ,下次 read 再解压读取剩下的,
GuuJiang
2022-01-05 19:39:27 +08:00
@asanelder 你这样读到 out 里的内容都是错误的,更别说长度了,一次 read 可能小于 1024 ,但是每次 write 都是写入整个 b 数组,导致多出了一些垃圾数据
Jwyt
2022-01-05 20:30:27 +08:00
@AoEiuV020CN 对 我忘了这一茬了
asanelder
2022-01-06 09:50:52 +08:00
@Jwyt #9
@GuuJiang #8
@AoEiuV020CN #7
@Jwyt #6
@codehz #5

感谢老铁们的耐心回答, 俺抽时间试试, 有了结果给各位说一声
asanelder
2022-01-06 10:29:04 +08:00
@AoEiuV020CN #4
@codehz #5
@Jwyt #6
@AoEiuV020CN #7
@GuuJiang #8

嗯, 确实是代码有问题, 俺按照铁子们的说法修改后

byte[] b = new byte[1024];
int len = in.read(b);
while(len != -1){
out.write(b, 0, len);
len = in.read(b);
}
log.info("data size = {}", data.length);

就正常了

至于具体原因~~~ 看样子还是得按照文档正确调用接口, 这样其行为才和预期一样. 至于之前没有指定 length 导致在 jar 中和非 jar 中形为不一致. 就忽略吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/826413

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX