【问题标题】:Is it possible to do CRC-32 calculation in splits?是否可以拆分进行 CRC-32 计算?
【发布时间】:2011-09-23 10:12:41
【问题描述】:

我使用这个简单的函数来计算给定文件的 CRC 校验和:

long i, j = 0;
int k = 0;
uint crc = 0xFFFFFFFF;
FileInfo file_info = new FileInfo(file);
byte[] file_buffer = new byte[32768];

FileStream file_stream = new FileStream(@file, FileMode.Open);
while ((i = file_stream.Read(file_buffer, 0, file_buffer.Count())) > 0)
{
    for (j = 0; j < i; j++)
    {
        uint before = crc;
        k = (int)((crc ^ file_buffer[j]) & 0x000000FFL);
        uint after = (uint)((crc >> 8) & 0x00FFFFFFL) ^ crc32_table[k];
        crc = after;
        uint test = (uint)((crc << 8) & 0x00FFFFFFL) ^ crc32_table[k];
        MessageBox.Show((~crc).ToString("X"));
    }
}
file_stream.Close();
return ~crc;

我的问题是:假设我有一个大文件,比如说 100MB。前 50MB 和后 50MB 的 CRC-32 计算与 100MB 文件的 CRC-32 计算之间是否存在联系?

我问的原因是,我有一些非常大的文件(大约 10GB 给或取)需要一些时间来生成,但是在生成它们时,大部分部分保持静态,但是,中间部分(已知点)和开始处(标题,也称为部分/长度)。计算 10GB 文件的 CRC-32 校验和需要相当长的时间,所以我想知道是否有任何方法可以分块进行?

【问题讨论】:

  • 是的,有可能。只要试着理解代码,你就会明白为什么。
  • 谢谢。你介意详细说明一下吗?我尝试将以前的 crc 值用作:private uint crc(string file, uint previous_value = 0xFFFFFFFF),但我得到了这些结果:a: 158094AD b: 68CD9474 ab: CD530E90 b2: 42A6F4F3,其中 b2 是 crc,其基值为 a 的 crcvalue。对不起!我的错。我不小心使用了 crc,而不是否定它 (~crc)。作品。非常感谢,leppie :)
  • 酷!很高兴帮助您“看到”答案:)
  • 您能否发表您的最后一条评论作为答案并接受它?这样问题就不再显示为未回答。
  • @Mik 提交您修改后的代码并接受它作为答案。

标签: c# crc32


【解决方案1】:

是的。有关示例,请参见 zlib 中的 crc32_combine_()

【讨论】:

    【解决方案2】:

    我知道这是一个老问题,但这是我用于“分块”CRC 计算的方法,以防万一这对任何人都有帮助:

    public static class Crc32Checksum
    {
        private static readonly uint[] Table = GenerateTable();
    
        /// <summary>
        /// Calculates a CRC32 value for the data given.
        /// </summary>
        /// <param name="data">Data contents</param>
        /// <param name="offset">Byte offset to start reading</param>
        /// <param name="count">Number of bytes to read</param>
        /// <returns>The computed CRC32 value.</returns>
        public static int Calculate(byte[] data, int offset, int count) 
            => Calculate(0, data, offset, count);
    
        /// <summary>
        /// Calculates a new CRC32 value given additional data for the current CRC value.
        /// </summary>
        /// <param name="currentCrc">The current CRC value to start with</param>
        /// <param name="data">Additional data contents</param>
        /// <param name="offset">Byte offset to start reading</param>
        /// <param name="count">Number of bytes to read</param>
        /// <returns>The computed CRC32 value.</returns>
        public static int Calculate(int currentCrc, byte[] data, int offset, int count)
        {
            unchecked
            {
                uint crc = ~(uint)currentCrc;
    
                for (int i = offset, end = offset + count; i < end; i++)
                    crc = (crc >> 8) ^ Table[(crc ^ data[i]) & 0xFF];
    
                return (int)~crc;
            }
        }
    
        private static uint[] GenerateTable()
        {
            unchecked
            {
                var table = new uint[256];
    
                const uint poly = 0xEDB88320;
    
                for (uint i = 0; i < table.Length; i++)
                {
                    uint crc = i;
    
                    for (int j = 8; j > 0; j--)
                    {
                        if ((crc & 1) == 1)
                            crc = (crc >> 1) ^ poly;
                        else
                            crc >>= 1;
                    }
    
                    table[i] = crc;
                }
    
                return table;
            }
        }
    }
    

    【讨论】:

    • 你检查过 crc(crc(0, "Hi "),"there") == crc(0, "Hi there") 吗?
    • 只是检查我的朋友,只是检查 ;-) 在发布我的问题后,我遵循了你的代码,我看到答案是肯定的。接受的答案应该是你的!谢谢迈克。
    • @Pat 没问题,很高兴你发现它有帮助!
    【解决方案3】:

    这个方程式很关键:

    CRC(a XOR b) == CRC(a) XOR CRC(b)
    

    假设您要计算以下消息的 CRC:

    "Always desire to learn something useful."
    

    存在计算 CRC 的函数:

    crc_join(crc_part1("Always desire to lea"),
             crc_part2("rn something useful."))
    

    如果 crc_part1crc_part2 用零填充 (\0) 他们的参数,如图所示,crc_join 只是 XOR。

    crc_part1 = crc("Always desire to lea\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")
    crc_part2 = crc("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0rn something useful.")
    

    可以使用查找表在crc_part1 中计算尾随零。 crc_part2 中的前导零可以忽略。

    参考资料:

    1. 基于软件的 CRC 的高速并行架构
      永珠。做,成禄。尹,太急。金,光义。 Pyun和Sin-Chong。公园
    2. https://en.wikipedia.org/wiki/Cyclic_redundancy_check

    【讨论】:

    • crc("WORD WORD ") != crc ("WORD ") XOR crc ("WORD ") 这才是真正重要的。这就是为什么我觉得你的方法有点误导。
    【解决方案4】:

    确实可以并行化 CRC-32 计算,但是细节很混乱,我需要花大约一天的时间来编写代码。

    让我们看一下基本的 CRC 算法,其中没有取反,也没有位反转。

    对于您要计算 CRC 的字节串,我们将其称为消息。基本思想是将消息视为GF(2) 中的多项式,然后以CRC 多项式为模计算其余数。

    基本的 CRC 算法是加法/线性的。如果有两条长度相同的消息 a 和 b,则 CRC(a XOR b) = CRC(a) XOR CRC(b)。

    此外,如果您在右侧用 n 个零填充消息,则新的 CRC 将是旧的 CRC 乘以 x^n mod CRC 多项式。

     

    话虽如此,解决您的问题的唯一方法是真正了解 CRC 算法背后的数学原理并编写您自己的自定义代码。下面是对 CRC 的一个很长但非常完整的解释:http://www.ross.net/crc/download/crc_v3.txt

    【讨论】:

    • 非常感谢您提供如此详细而精彩的概念介绍。
    • 在另一篇文章中,我详细解释了 CRC-32 与多项式除法(即异或、填充和反转)有何不同:stackoverflow.com/questions/5047494/python-crc32-woes/…
    • 我想知道如果我在不同的网络层执行多个 CRC,那么整个未检测到的错误可能是什么?并且在数据包大小上做 32 位,同时在块大小(包含多个数据包)上做 64 位有助于检测错误?
    猜你喜欢
    • 2011-04-16
    • 1970-01-01
    • 1970-01-01
    • 2019-05-21
    • 2020-12-18
    • 2011-05-15
    • 2014-11-20
    • 2014-01-15
    • 1970-01-01
    相关资源
    最近更新 更多