是否可以在拆分中进行CRC-32计算?

时间:2011-06-27 11:00:46

标签: c# crc32

我使用这个简单的函数来计算给定文件的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校验和需要相当长的时间,所以我想知道是否有任何方法可以在块中进行?

4 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:2)

确实可以并行化CRC-32计算,但细节很混乱,我需要花一天时间来提出代码。

让我们看看基本的CRC算法,其中没有否定和没有位反转。

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

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

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

尽管如此,解决问题的唯一方法是真正理解CRC算法背后的数学并编写自己的自定义代码。以下是对CRC的详尽解释:http://www.ross.net/crc/download/crc_v3.txt

答案 2 :(得分:2)

这个等式是关键:

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只是异或。

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的高速并行架构
    Youngju。做,Sung-Rok。尹,Taekyu。 Kim,Kwang Eui。 Pyun和Sin-Chong。园
  2. https://en.wikipedia.org/wiki/Cyclic_redundancy_check

答案 3 :(得分:1)

我知道这是一个老问题,但这是我用于“分块” 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;
        }
    }
}