计算微信下载回单文件的哈希值,以确认下载账单数据的完整性

举报
悟空码字 发表于 2025/12/15 10:08:28 2025/12/15
【摘要】 微信回单文件的哈希值,是微信支付为商户下载的电子回单文件生成的一个固定长度且唯一的字符串,也常被称为“数字指纹”。它主要用于验证回单文件的完整性和真实性。

大家好,我是小悟。

微信回单文件的哈希值,是微信支付为商户下载的电子回单文件生成的一个固定长度且唯一的字符串,也常被称为“数字指纹”。它主要用于验证回单文件的完整性和真实性。

可靠的哈希函数具有“雪崩效应”,即原始数据哪怕只发生一个比特的改变,计算出的哈希值也会截然不同。这使得它极其灵敏,能够有效发现文件的任何改动。

处理微信的回单文件并计算其哈希值,通常涉及获取文件、选择算法和实际计算几个步骤。

1. 基础版本 - 计算文件MD5SHA-256

import java.io.FileInputStream;
import java.security.MessageDigest;
import java.util.HexFormat;

public class WechatBillDigest {

    /**
     * 计算文件的MD5摘要值
     */
    public static String calculateMD5(String filePath) throws Exception {
        return calculateDigest(filePath, "MD5");
    }

    /**
     * 计算文件的SHA-256摘要值
     */
    public static String calculateSHA256(String filePath) throws Exception {
        return calculateDigest(filePath, "SHA-256");
    }

    /**
     * 通用摘要计算方法
     */
    private static String calculateDigest(String filePath, String algorithm) throws Exception {
        MessageDigest digest = MessageDigest.getInstance(algorithm);

        try (FileInputStream fis = new FileInputStream(filePath)) {
            byte[] buffer = new byte[8192];
            int bytesRead;

            while ((bytesRead = fis.read(buffer)) != -1) {
                digest.update(buffer, 0, bytesRead);
            }
        }

        byte[] hashBytes = digest.digest();
        return HexFormat.of().formatHex(hashBytes);
    }
}

2. 完整工具类(支持多种算法)

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HexFormat;

public class WechatBillDigestUtil {

    public enum DigestAlgorithm {
        MD5("MD5"),
        SHA1("SHA-1"),
        SHA256("SHA-256"),
        SHA512("SHA-512");

        private final String algorithm;

        DigestAlgorithm(String algorithm) {
            this.algorithm = algorithm;
        }

        public String getAlgorithm() {
            return algorithm;
        }
    }

    /**
     * 计算微信回单文件的摘要值
     */
    public static String calculateDigest(File file, DigestAlgorithm algorithm) 
            throws NoSuchAlgorithmException, IOException {

        if (!file.exists()) {
            throw new IOException("文件不存在: " + file.getAbsolutePath());
        }

        if (!file.isFile()) {
            throw new IOException("路径不是文件: " + file.getAbsolutePath());
        }

        MessageDigest digest = MessageDigest.getInstance(algorithm.getAlgorithm());

        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[8192];
            int bytesRead;

            while ((bytesRead = fis.read(buffer)) != -1) {
                digest.update(buffer, 0, bytesRead);
            }
        }

        byte[] hashBytes = digest.digest();
        return HexFormat.of().formatHex(hashBytes);
    }

    /**
     * 批量计算多种摘要值
     */
    public static void calculateAllDigests(String filePath) {
        File file = new File(filePath);

        if (!file.exists()) {
            System.out.println("文件不存在: " + filePath);
            return;
        }

        System.out.println("文件: " + file.getName());
        System.out.println("大小: " + file.length() + " 字节");
        System.out.println("最后修改: " + new java.util.Date(file.lastModified()));
        System.out.println("----------------------------------------");

        for (DigestAlgorithm algorithm : DigestAlgorithm.values()) {
            try {
                String digest = calculateDigest(file, algorithm);
                System.out.printf("%-8s: %s%n", algorithm.name(), digest);
            } catch (Exception e) {
                System.out.printf("%-8s: 计算失败 - %s%n", algorithm.name(), e.getMessage());
            }
        }
    }
}

3. 带进度显示的高级版本

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.text.DecimalFormat;

public class WechatBillDigestWithProgress {

    /**
     * 带进度显示的文件摘要计算
     */
    public static String calculateDigestWithProgress(String filePath, String algorithm) 
            throws Exception {

        File file = new File(filePath);
        if (!file.exists()) {
            throw new IOException("文件不存在: " + filePath);
        }

        long fileSize = file.length();
        MessageDigest digest = MessageDigest.getInstance(algorithm);

        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[8192];
            int bytesRead;
            long totalRead = 0;
            long lastProgress = -1;

            System.out.println("开始计算文件摘要...");
            System.out.println("文件大小: " + formatFileSize(fileSize));

            while ((bytesRead = fis.read(buffer)) != -1) {
                digest.update(buffer, 0, bytesRead);
                totalRead += bytesRead;

                // 显示进度(每10%更新一次)
                int progress = (int) ((totalRead * 100) / fileSize);
                if (progress != lastProgress && progress % 10 == 0) {
                    System.out.printf("计算进度: %d%%%n", progress);
                    lastProgress = progress;
                }
            }

            System.out.println("计算完成: 100%");
        }

        byte[] hashBytes = digest.digest();
        return bytesToHex(hashBytes);
    }

    /**
     * 字节数组转十六进制字符串
     */
    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    /**
     * 格式化文件大小
     */
    private static String formatFileSize(long size) {
        if (size <= 0) return "0 B";
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) 
                + " " + units[digitGroups];
    }
}

4. 使用示例

public class WechatBillDigestExample {

    public static void main(String[] args) {
        String filePath = "path/to/wechat/bill.csv"; // 替换为实际文件路径

        try {
            // 方法1: 基础使用
            String md5 = WechatBillDigest.calculateMD5(filePath);
            String sha256 = WechatBillDigest.calculateSHA256(filePath);

            System.out.println("MD5: " + md5);
            System.out.println("SHA-256: " + sha256);
            System.out.println();

            // 方法2: 使用工具类计算所有摘要
            WechatBillDigestUtil.calculateAllDigests(filePath);
            System.out.println();

            // 方法3: 带进度显示
            String digestWithProgress = WechatBillDigestWithProgress
                    .calculateDigestWithProgress(filePath, "SHA-256");
            System.out.println("最终摘要值: " + digestWithProgress);

        } catch (Exception e) {
            System.err.println("计算摘要时出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

5. Maven依赖(如果需要第三方库)

<dependencies>
    <!-- Apache Commons Codec 提供更多摘要算法支持 -->
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.16.0</version>
    </dependency>
</dependencies>

多种算法支持:MD5、SHA-1、SHA-256、SHA-512

大文件优化:使用缓冲区读取,避免内存溢出

进度显示:可显示计算进度

异常处理:完善的错误处理机制

格式规范:输出标准的十六进制字符串

计算微信下载回单文件的哈希值,以确认下载账单数据的完整性.jpg

谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。

您的一键三连,是我更新的最大动力,谢谢

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。