Java生成与UNIX cksum一致的校验值失败问题排查
为什么Java生成的校验值和UNIX cksum不一致?
哎,这个问题我之前也踩过坑!你用Java自带的CRC32类来模拟UNIX的cksum命令,结果不一样的核心原因是:UNIX的cksum用的不是标准CRC32算法,而是它专属的变种实现。
具体差异在哪里?
UNIX cksum的CRC计算逻辑和Java标准CRC32有两个关键不同:
- 初始值:UNIX cksum的CRC初始值是
0xFFFFFFFF,而JavaCRC32的初始值是0 - 最终处理:UNIX cksum会对计算后的CRC值取反(等价于异或
0xFFFFFFFF),Java标准实现没有这一步
另外还要提一句,如果你的文件在Windows和UNIX之间传输时,换行符从CRLF变成了LF,文件大小会变化,这也会导致cksum结果不同,但看你给出的输出,两边文件大小都是8335,所以这个问题这次不存在,但以后要留意。
修正后的代码实现
我们可以自己实现一个符合UNIX cksum规则的CRC32校验类,替换掉Java自带的CRC32:
package cksum; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.zip.CheckedInputStream; import java.util.zip.Checksum; public class CksumFix { public static void main(String[] args) throws IOException { String fileName = "C:\\Users\\admin\\Desktop\\logback XMLs\\STG_logback_Debug_All.xml"; doChecksum32(fileName); } private static void doChecksum32(String fileName) { try { // 使用自定义的UnixCrc32替代Java原生CRC32 CheckedInputStream cis = new CheckedInputStream( new FileInputStream(fileName), new UnixCrc32()); long fileSize = new File(fileName).length(); byte[] buf = new byte[128]; while (cis.read(buf) >= 0) { // 读取所有字节完成校验计算 } long checksum = cis.getChecksum().getValue(); System.out.println(checksum + " " + fileSize + " " + fileName); } catch (FileNotFoundException e) { System.err.println("File not found."); System.exit(1); } catch (IOException e) { e.printStackTrace(); System.exit(1); } } // 实现符合UNIX cksum规范的CRC32变种 static class UnixCrc32 implements Checksum { // CRC32标准多项式 private static final long POLY = 0xEDB88320L; // 初始值符合UNIX cksum要求 private long crc = 0xFFFFFFFFL; @Override public void update(int b) { crc ^= b & 0xFF; for (int i = 0; i < 8; i++) { if ((crc & 1) != 0) { crc = (crc >>> 1) ^ POLY; } else { crc >>>= 1; } } } @Override public void update(byte[] b, int off, int len) { for (int i = off; i < off + len; i++) { update(b[i]); } } @Override public long getValue() { // 最后对CRC值取反,得到UNIX cksum的结果 return ~crc; } @Override public void reset() { crc = 0xFFFFFFFFL; } } }
为什么这样改能生效?
这个自定义的UnixCrc32类严格遵循了UNIX cksum的CRC计算规则:
- 初始化CRC值为
0xFFFFFFFF,和UNIX的实现对齐 - 使用标准CRC32的多项式进行位运算
- 最终返回结果前对CRC值取反,补上UNIX要求的最后一步
运行这个修正后的代码,得到的校验值就会和UNIXcksum命令的输出一致了!
内容的提问来源于stack exchange,提问作者AKPuvvada
相关产品推荐
相关产品推荐

