我使用这个简单的函数来计算给定文件的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校验和需要相当长的时间,所以我想知道是否有任何方法可以在块中进行?
答案 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_part1
和crc_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
中可以忽略前导零。
参考文献:
答案 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;
}
}
}