2012-02-24 70 views
1

这里我使用两种不同的函数来计算任何类型文件的CRC16 (.txt,.tar,.tar.gz,.bin,.scr,.sh etc),不同的大小也从1 KB to 5 GB变化。对于任何类型的文件,计算CRC16时哪种数据类型更好

我想要实现这个

`cross platform 

    less time consuming 

    Have to work proper for any type of file and any size` 

我得到了这两种功能的CRC值相同。但任何人都可以告诉我哪个更适合计算任何类型的文件在不同平台上的任何大小的CRC16 CRC16。

这里我们必须考虑0到255所有类型的字符。

任何机构可以请我建议我哪一个在我的要求是好的。

代码的两种功能:

其在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 < 8; intInnerLoopIndex++) { 
      if ((result & 0x0001) == 0x0001) { 
       result = result >> 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 < 8; intInnerLoopIndex++) { 
        if ((result & 0x0001) == 0x0001) { 
         result = result >> 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); 
} 

请帮我看看URE出这个问题

感谢

+0

16位CRC不足以涵盖从1K到5GB的文件。对于这样的大数据块,即使有数据错误,CRC匹配的概率也很高。 – TJD 2012-02-24 17:37:05

回答

2

第一件事是第一件事。不要在同一个函数中进行文件读取(或任何源代码)和CRC计算。这是糟糕的设计。文件读取通常不是完全平台独立的(尽管POSIX是你最好的朋友),但是CRC计算可以独立完成。此外,您可能希望重复使用您的CRC算法来处理其他类型的数据源,这些数据源不通过fopen()进行访问。

为了给你一个提示,在CRC功能我一直在下降到我的项目有这个原型:

uint16_t Crc16(const uint8_t* buffer, size_t size, 
          uint16_t polynomial, uint16_t crc); 

你不必一次调用该函数并给它的文件的全部内容。相反,您可以循环访问块中的文件并调用每个块的功能。在你的情况下,参数polynomial0xA001(这是BTW多项式的“反转”形式),并且crc参数首次设置为0xFFFF。随后每次调用该函数时,都会将该函数的前一个返回值传递给crc参数。

在您的第二个代码段(CRC16_unchar)中,首先确定文件大小,然后读取该字节数。不要这样做,它不必要限制您处理最大4GB的文件(在大多数情况下)。只是阅读,直到EOF更清洁恕我直言。

此外,我看到你正在努力与签署/无符号字节。知道

  • printf不知道您是否传递了一个有符号或无符号的整数。你用'%d'或'%u'告诉printf如何解释整数。
  • 即使在C本身,有符号和无符号整数之间几乎没有区别。如果你做int8_t x = 255,C不会奇迹般地将255的值更改为-1。

有关C何时使用整数的符号性的更多详细信息,请参阅此脚本:When does the signedness of an integer really matter?。经验法则:总是使用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) 
+1

'result^=(short)(readChar);'中的第一个函数没有问题;'因为'readChar'是一个'int'?字符可能具有0 ... 127范围以外的值,并在转换为“int”或“short”时导致符号扩展。 – 2012-02-24 10:20:26

+0

@亚历克斯:的确,在考虑签署签名时。我忘记了这一点(并且也查看了该代码行)。我会编辑我的答案。 – Bart 2012-02-24 10:32:04

+0

我只是再次检查标准,感谢@ user1089679,'getc()/ fgetc()'在内部转换为'unsigned char',所以在这里不应该是个问题。 – 2012-02-24 10:53:11

1

你想用unsigned char而不是纯char因为char既可以签署或无符号的读取和写入的8位字节,这就是到编译器(C标准允许) 。因此,在用于CRC计算之前,您从getc()获得的值应该转换为unsigned char。你也可以将fread()转换为unsigned char。如果您使用带符号的字符,将字符扩展名签入可能会破坏您的CRC计算。

另外,根据C标准fseek(FilePtr, 0, SEEK_END)对于二进制流具有未定义的行为,并且二进制流不需要有意义地支持SEEK_ENDfseek()中。但实际上,这通常是我们想要的。

你应该考虑的另一件事是检查I/O错误。你的代码在这方面被打破了。

+0

但是在这里fgetc总是返回unsinged字符,所以它永远不会给出有符号字符 – user1089679 2012-02-24 10:35:50

+0

@ user1089679:只需再次检查标准,你是对的。 – 2012-02-24 10:49:01

+0

你可以告诉我哪一个更好吗可能是我认为无符号字符一个更好 – user1089679 2012-02-24 10:55:14

0

在我看来,您应该进行计算的数据类型应与您从文件中读取的数据类型不同。对运行时库执行一个函数调用来读取单个字节效率不高。您应该一次读取2-4 KB的顺序,然后以您选择的任何方式遍历每个返回的“块”。

还有在预先读取的文件的大小完全没有意义的,你应该简单地看,直到读返回更少的数据低于预期,在这种情况下,你可以检查feof()ferror()弄清楚做什么,通常只是停止,因为你完成了。请参阅fread()手册页。