FIT文件CRC校验

校验FIT文件CRC代码做个记录,分为两步先校验头部然后再校验整个FIT文件。校验头部不是必需的看个人需要吧。为了偷懒使用Okio库,还有计算CRC的时候用的Garmin的FitSDK。

public class FitUtils {
    /**
     * 校验Fit文件,首先校验头部然后校验数据
     *
     * @param file
     * @return
     */
    public static boolean checkFitFile(File file) {
        BufferedSource source = null;
        try {
            final int MAX_HEADER_LEN = 14;
            source = Okio.buffer(Okio.source(file));
            byte[] header = new byte[MAX_HEADER_LEN - 2];
            header[0] = source.readByte();
            int headerLen = header[0];
            if (headerLen <= 0 || headerLen > MAX_HEADER_LEN)
                return false;
            source.read(header, 1, header.length - 1); //去除头长度和crc
            //验证头部
            if (headerLen == MAX_HEADER_LEN) {
                short fileCrc16 = source.readShortLe();
                if (fileCrc16 != 0) {    //FIT允许HEADER的CRC为0
                    int crc16 = getCRC16(header, 0, header.length);
                    if (crc16 != fileCrc16)
                        return false;
                }
            }
            //校验数据
            source.close();
            source = Okio.buffer(Okio.source(file));
            int crc16ForData = 0;
            for (int crcByte = 0; crcByte < file.length() - 2; crcByte++) {
                crc16ForData = CRC.get16(crc16ForData, source.readByte());
            }
            short originCRC16 = source.readShortLe();
            return originCRC16 == (short) crc16ForData;
        } catch (IOException e) {
            if (BuildConfig.DEBUG)
                e.printStackTrace();
        } finally {
            if (source != null) {
                try {
                    source.close();
                } catch (IOException e) {
                    if (BuildConfig.DEBUG)
                        e.printStackTrace();
                }
            }
        }
        return false;
    }
    public static short getCRC16(byte[] data, int offset, int len) {
        int crc16 = 0;
        for (int index = offset; index < (offset + len); index++) {
            crc16 = CRC.get16(crc16, data[index]);
        }
        return (short) crc16;
    }
}

转载于:https://www.cnblogs.com/xwgblog/p/5769553.html

<think>好的,我现在要解决用户提出的“varint exceeds range”的问题。首先,我需要确varint是什么,以及为什么会出现超出范围的情况。varint是一种可变长度的整数编码方式,通常用于节省存储空间。比如Protocol Buffers中就使用了varint来编码整数。用户遇到的问题可能是在使用类似技术时,输入的数值超过了varint能表示的范围。 接下来,我需要回忆varint的编码规则。varint使用每个字节的最高位作为标志位,表示是否还有后续字节。剩下的7位用于存储数值。因此,对于无符号的varint,最大值是$2^{28}-1$(如果有4个字节的话)或者更长的字节数。不过具体实现可能有不同的限制,比如Protocol Buffers中的int32用varint表示时,实际范围是-2^31到2^31-1,而uint32则是0到2^32-1。如果用户试图存储超过这些范围的数值,就会出现超出范围的错误。 用户可能的情况包括:在序列化时传入了超过允许范围的数值,或者在反序列化时数据损坏导致解析出的数值超出预期。需要分情况讨论解决方案。 首先,检查输入值是否在目标数据类型的有效范围内。比如,如果使用int32,应确保数值在$-2^{31}$到$2^{31}-1$之间。如果是uint64,则应为0到$2^{64}-1$。如果输入值超出范围,需要调整数值或使用更大的数据类型,比如int64或uint64。 其次,检查数据是否正确序列化和反序列化。可能存在编码或解码过程中的错误,导致数值被错误解析。比如,在处理有符号数时,varint使用ZigZag编码,如果解码时没有正确应用ZigZag解码,可能导致数值错误。 另外,数据损坏或传输错误也可能引发此问题。验证数据完整性,比如使用校验和或重传机制,可以避免这类问题。 对于特定系统如数据库或存储引擎,可能需要调整架构。例如,引用[3]提到的分层存储,将热点数据放在更靠近顶层的层级,可能影响数据处理的性能,但和varint范围问题关系不大。不过,如果存储结构设计不当,可能导致数据分片处理时数值溢出,需要检查数据分区策略。 总结解决方案步骤:1. 检查输入值范围;2. 调整数据类型;3. 验证编解码逻辑;4. 确保数据完整性;5. 调整系统设计如使用更大的类型或分片处理。 最后,生成相关问题,覆盖数据类型的选择、编解码实现、调试方法以及相关存储优化等。</think>关于解决“varint exceeds range”的问题,以下是具体分析和解决方案: ### 1. 理解varint的范围限制 varint(可变长度整数)通过多个字节表示整数,每个字节最高位标识是否继续读取下一个字节,剩余7位存储数值。例如: - **无符号varint**:若使用4字节,最大值为$2^{28}-1$(每个字节7位,共$7 \times 4 = 28$位)。 - **有符号varint**:通常结合ZigZag编码,将负数映射到无符号范围,例如int32的范围是$-2^{31}$到$2^{31}-1$[^1]。 若数值超出目标类型范围(如将$10^{10}$存入int32),系统会抛出“varint exceeds range”错误。 --- ### 2. 解决方案 #### 步骤1:检查输入值的有效范围 - **示例**:若使用Protocol Buffers的`int32`,需确保数值在$[-2^{31}, 2^{31}-1]$之间。 - **调整方法**:改用更大类型如`int64`或`uint64`,其范围分别为$[-2^{63}, 2^{63}-1]$和$[0, 2^{64}-1]$。 #### 步骤2:验证编解码逻辑 - **编码错误**:未正确处理负数时,可能错误地编码为超大无符号数。需确认是否应用ZigZag编码。 - **解码错误**:读取字节时未正确解析标志位,导致数值溢出。检查代码逻辑是否匹配规范。 #### 步骤3:处理数据完整性问题 - **数据损坏**:网络传输或存储错误可能导致varint字节错误。可通过校验和(如CRC32)或重传机制解决[^2]。 - **边界测试**:在单元测试中添加边界值(如最大值+1)验证系统行为。 #### 步骤4:调整系统设计 - **分片存储**:若单次操作数据量过大,可将数据分片处理,避免单值超出范围。例如引用[3]提到的分层存储,将大块数据拆分到不同层级。 - **类型升级**:在数据库或协议中升级字段类型(如从int32改为int64)。 --- ### 3. 示例代码(Protocol Buffers语法) ```protobuf // 原定义(可能引发范围错误) message Example { int32 value = 1; // 最大值为2^31-1 (2147483647) } // 修改后定义 message FixedExample { int64 value = 1; // 支持更大范围[-2^63, 2^63-1] } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值