对于任何类型的文件,哪种数据类型更适合计算CRC16
这里我使用两个不同的函数来计算任何类型文件(.txt,.tar,.tar.gz,.bin,.scr,.sh etc)
CRC16,不同的大小也从1 KB to 5 GB
不等。
我想实现这一目标
`cross platform less time consuming Have to work proper for any type of file and any size`
我在两个函数中都获得了相同的CRC值。 但任何人都可以告诉我哪个更好的计算任何类型的文件在不同的不同平台上的任何类型的文件CRC16。
这里我们要考虑0到255所有类型的字符。
任何人都可以建议我哪一个符合我的要求。
两种function的代码:
第一个在readChar
有int
数据类型的我在这里使用int readChar
int CRC16_int(const char* filePath) { //Declare variable to store CRC result. unsigned short result; //Declare loop variables. int intInnerLoopIndex; result = 0xffff; //initialize result variable to perform CRC checksum calculation. //Store message which read from file. //char content[2000000]; //Create file pointer to open and read file. FILE *readFile; //Use to read character from file. int readChar; //open a file for Reading readFile = fopen(filePath, "rb"); //Checking file is able to open or exists. if (!readFile) { fputs("Unable to open file %s", stderr); } /* Here reading file and store into variable. */ int chCnt = 0; while ((readChar = getc(readFile)) != EOF) { //printf("charcater is %c\n",readChar); //printf("charcater is %c and int is %d \n",readChar,readChar); result ^= (short) (readChar); for (intInnerLoopIndex = 0; intInnerLoopIndex > 1; //Perform bit shifting. result = result ^ 0xa001; //Perform XOR operation on result. } else { result = result >> 1; //Perform bit shifting. } } //content[chCnt] = readChar; chCnt++; } printf("\nCRC data length in file: %d", chCnt); //This is final CRC value for provided message. return (result); }
第二个是readChar
unsigned char
数据类型这里我使用unsigned char readChar
int CRC16_unchar(const char* filePath) { unsigned int filesize; //Declare variable to store CRC result. unsigned short result; //Declare loop variables. unsigned int intOuterLoopIndex, intInnerLoopIndex; result = 0xffff; //initialize result variable to perform CRC checksum calculation. FILE *readFile; //Use to read character from file. //The problem is if you read a byte from a file with the hex value (for example) 0xfe, //then the char value will be -2 while the unsigned char value will be 254. //This will significantly affect your CRC unsigned char readChar; //open a file for Reading readFile = fopen(filePath, "rb"); //Checking file is able to open or exists. if (!readFile) { fputs("Unable to open file %s", stderr); } fseek(readFile, 0, SEEK_END); // seek to end of file filesize = ftell(readFile); // get current file pointer fseek(readFile, 0, SEEK_SET); // seek back to beginning of file /* Here reading file and store into variable. */ int chCnt = 0; for (intOuterLoopIndex = 0; intOuterLoopIndex < filesize; intOuterLoopIndex++) { readChar = getc(readFile); printf("charcater is %c and int is %d\n",readChar,readChar); result ^= (short) (readChar); for (intInnerLoopIndex = 0; intInnerLoopIndex > 1; //Perform bit shifting. result = result ^ 0xa001; //Perform XOR operation on } else { result = result >> 1; //Perform bit shifting. } } chCnt++; } printf("\nCRC data length in file: %d", chCnt); return (result); }
请帮我解决这个问题
谢谢
首先要做的事情。 不要在同一个函数中进行文件读取(或任何源)和CRC计算。 这是糟糕的设计。 文件读取通常不是完全独立于平台的(尽管POSIX是您最好的朋友),但CRC计算可以在非常平台上独立完成。 此外,您可能希望将CRC算法重用于不使用fopen()
访问的其他类型的数据源。
为了给你一个提示,我总是参与我的项目的CRC函数有这个原型:
uint16_t Crc16(const uint8_t* buffer, size_t size, uint16_t polynomial, uint16_t crc);
您不必一次调用该函数并将其提供给文件的完整内容。 相反,您可以在块中循环遍历文件并为每个块调用函数。 您的情况下的polynomial
参数是0xA001
(BTW是’反向’forms的多项式), crc
参数第一次设置为0xFFFF
。 每次调用该函数时,都会将函数的上一个返回值传递给crc
参数。
在第二个代码片段( CRC16_unchar
)中,首先确定filesize然后读取该字节数。 不要这样做,它不必限制你处理最大4GB的文件(在大多数情况下)。 只是阅读直到EOF更清洁恕我直言。
此外,我发现你正在努力使用有符号/无符号字节。 知道吗
-
printf
不知道您是否传递有符号或无符号整数。 你告诉printf
‘%d’或’%u’如何解释整数。 - 即使在C本身中,有符号整数和无符号整数之间几乎没有区别。 如果你执行
int8_t x = 255
C不会神奇地将255的值更改为-1。
有关何时C使用整数的有符号性的更多详细信息,请参阅此anser:整数的有效性何时真正重要? 。 经验法则:只需始终使用uint8_t
处理原始字节。
所以这两个函数在签名/整数大小方面都很好。
编辑:正如其他用户在他们的答案中指出的那样,以块为单位而不是每个字节读取文件:
uint16_t CRC16_int(const char* filePath) { FILE *readFile; const uint8_t buf[1024]; size_t len; uint16_t result = 0xffff;; /* Open a file for reading. */ readFile = fopen(filePath, "rb"); if (readFile == NULL) { exit(1); } /* Read until EOF. */ while ( (len = fread(buf, sizeof(buf), 1, readFile)) > 0 ) { result = Crc16(buf, len, 0xA001, result); } /* readFile could be in error state, check it with ferror() or feof() functions. */ return result; }
您还应该更改函数原型以使返回错误成为可能,例如:
// Return true when successful, false on error. CRC is stored in result. bool CRC16_int(const char* filePath, uint16_t *result)
您希望使用unsigned char
而不是plain char
来读取和写入8位字节,因为char
可以是有符号或无符号的,这取决于编译器(C标准允许)。 因此,在用于CRC计算之前,应将getc()
获得的值转换为unsigned char
。 你也可以将fread()
转换为unsigned char
。 如果您使用签名字符,将字符符号扩展为整数可能会破坏您的CRC计算。
此外,根据C标准fseek(FilePtr, 0, SEEK_END)
具有二进制流的未定义行为,二进制流无需在fseek()
有意义地支持SEEK_END
。 但实际上,这通常可以按照我们的意愿运作。
您应该考虑的另一件事是检查I / O错误。 你的代码在这方面被打破了。
在我看来,你进行计算的数据类型应该与你从文件中读取的数据类型不同。 对运行时库执行一个函数调用以读取单个字节根本效率不高。 您应该一次读取2-4 KB的顺序,然后以您选择的任何方式迭代每个返回的“块”。
事先读取文件的大小也绝对没有意义,你应该阅读直到阅读返回的数据少于预期,在这种情况下你可以检查feof()
和ferror()
来弄清楚要做什么,通常只是你做完就停止了。 请参阅fread()
手册页。