C/C++给文件加crc校验

简介: C/C++给文件加crc校验

概述


CRC16/32校验是常用的一种校验方法,crc16需要区分多项式,不同多项式的校验结果是不一样的,

如果是对通信数据做校验,那收发两端的crc16一定要匹配,否则校验不通过。


对文件加crc校验


对文件加crc校验的的目的也是为了验证文件的完整性。添加crc校验是一种简单的验证方式。


这里用到一个小技巧:就是把文件数据的校验码追加在文件的最后,这样既不会影响文件的数据,

也不影响文件属性,并且也方便检查,不需要额外在加一个文件。


代码


#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
 
using namespace std;
 
/*
 * 附录 A:循环冗余校验(CRC)算法
 * CRC 校验(Cyclic Redundancy Check)是一种数据传输错误检查方法, CRC 码两个字
 * 节,包含一 16 位的二进制值。它由传输设备计算后加入到数据包中。接收设备重新计算收
 * 到消息的 CRC,并与接收到的 CRC 域中的值比较,如果两值不同,则有误。
 * 具体算法如下:
 * CRC 是先调入一值是全“1”的 16 位寄存器,然后调用一过程将消息中连续的 8 位字
 * 节各当前寄存器中的值进行处理。仅每个字符中的 8Bit 数据对 CRC 有效,起始位和停止位
 * 以及奇偶校验位均无效。
 * CRC 校验字节的生成步骤如下:
 * ① 装一个 16 位寄存器,所有数位均为 1。
 * ② 取被校验串的一个字节与 16 位寄存器的高位字节进行“异或”运算。运算结果放
 * 入这个 16 位寄存器。
 * ③ 把这个 16 寄存器向右移一位。
 * ④ 若向右(标记位)移出的数位是 1,则生成多项式 1010 0000 0000 00Q01 和这个寄
 * 存器进行“异或”运算;若向右移出的数位是 0,则返回③。
 * ⑤ 重复③和④,直至移出 8 位。
 * ⑥ 取被校验串的下一个字节
 * ⑦ 重复③~⑥,直至被校验串的所有字节均与 16 位寄存器进行“异或”运算,并移位
 * 8 次。
 * ⑧ 这个 16 位寄存器的内容即 2 字节 CRC 错误校验码。
 * 校验码按照先高字节后低字节的顺序存放。
 *
 *
 *
 * */
unsigned short crc16(const unsigned char *ptr, int len)        // ptr 为数据指针,len 为数据长度 
{ 
 
  unsigned int i;
  unsigned short j,tmp,CRC16;
 
  CRC16=0xffff;
  for ( i = 0; i < len; i++ )
  {  
      CRC16 = *ptr ^ CRC16;
      for ( j = 0; j < 8; j++ )
      {
      tmp=CRC16 & 0x0001;
      CRC16 =CRC16 >>1;
      if (tmp)
        CRC16=CRC16 ^ 0xa001;    
    }
    *ptr++;
  } 
 
  return(CRC16);
}
 
unsigned short checkFile( const string &file)
{
  struct stat stFileStat;
  
  int ret =  stat(file.c_str(), &stFileStat);
  if ( ret < 0 )
  {
    perror("stat error");
    return false;
  }
 
  cout<<"file size = "<<stFileStat.st_size<<endl;
 
  char *p = new char [stFileStat.st_size+2];
  
  FILE *fp = fopen(file.c_str(), "r");
  if ( fp == NULL )
  {
    perror("fopen file error");
    return -1;
  }
  
  ret = fread(p,  stFileStat.st_size, 1, fp);
  if (ret != 1)
  {
    perror("fread error");
    return -1;
  }
  
  fclose(fp);
  unsigned short crc16Data = crc16((unsigned char *)p, stFileStat.st_size);
  printf("file crc16 = 0x%04x\n", crc16Data);
  
  delete [] p;
 
  return crc16Data;
}
 
int main(int argc, char **argv)
{
  if ( argc <= 1 )
  {
    printf("Uage: %s <file>", argv[0]);
    return -1;
  }
  
  string file=argv[1];
  if (file == "-c")
  {
    return checkFile(argv[2]);
  }
  
  struct stat stFileStat;
  
  int ret =  stat(file.c_str(), &stFileStat);
  if ( ret < 0 )
  {
    perror("stat error");
    return false;
  }
 
  cout<<"file size = "<<stFileStat.st_size<<endl;
 
  char *p = new char [stFileStat.st_size+2];
  
  FILE *fp = fopen(file.c_str(), "r");
  if ( fp == NULL )
  {
    perror("fopen file error");
    return -1;
  }
  
  ret = fread(p,  stFileStat.st_size, 1, fp);
  if (ret != 1)
  {
    perror("fread error");
    return -1;
  }
  
  fclose(fp);
  unsigned short crc16Data = crc16((unsigned char *)p, stFileStat.st_size);
  printf("file crc16 = 0x%04x\n", crc16Data);
  
  p[stFileStat.st_size] = crc16Data & 0xff;
  p[stFileStat.st_size+1] = (crc16Data >> 8) & 0xff;
  
  crc16Data = crc16((unsigned char *)p, stFileStat.st_size+2);
  
  if ( crc16Data != 0)
    cout<<"check file crc16 fault! please add crc16 later!"<<endl;
  
  file += ".crc16";
  fp = fopen(file.c_str(), "w");
  if ( fp == NULL )
  {
    perror("fopen file error");
    return -1;
  }
  
  ret = fwrite(p,  stFileStat.st_size+2, 1, fp);
  if (ret != 1)
  {
    perror("fwrite error");
    return -1;
  }
  
  fclose(fp);
  
  delete [] p;
  
  cout<<"add  crc16 ok! "<<endl;
 
  
}
目录
相关文章
|
1月前
|
存储 C++
基于C++的简易文件压缩与解压缩工具设计与实现
基于C++的简易文件压缩与解压缩工具设计与实现
43 3
|
2天前
|
C++
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
2 0
C++职工管理系统(类继承、文件、指针操作、中文乱码解决)
|
4天前
|
C++ iOS开发 开发者
C++一分钟之-文件输入输出(I/O)操作
【6月更文挑战第24天】C++的文件I/O涉及`ifstream`, `ofstream`和`fstream`类,用于读写操作。常见问题包括未检查文件打开状态、忘记关闭文件、写入模式覆盖文件及字符编码不匹配。避免这些问题的方法有:检查`is_open()`、显式关闭文件或使用RAII、选择适当打开模式(如追加`ios::app`)以及处理字符编码。示例代码展示了读文件和追加写入文件的实践。理解这些要点能帮助编写更健壮的代码。
14 2
|
22天前
|
编译器 C语言 C++
C++中.h和.hpp文件有什么区别?
C++中.h和.hpp文件有什么区别?
|
1天前
|
存储 分布式数据库 API
技术好文:VisualC++查看文件被哪个进程占用
技术好文:VisualC++查看文件被哪个进程占用
|
1天前
|
IDE 开发工具 C++
插件:CLion中使用C/C++ Single File Execution插件编译和运行单个文件
插件:CLion中使用C/C++ Single File Execution插件编译和运行单个文件
7 0
|
1月前
|
C++ 数据格式
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
【C++】C++中的【文件IO流】使用指南 [手把手代码演示] & [小白秒懂]
|
22天前
|
Linux C++
Linux C/C++目录和文件的更多操作
Linux C/C++目录和文件的更多操作
|
22天前
|
NoSQL Linux C++
Linux C/C++ gdb调试core文件
Linux C/C++ gdb调试core文件
|
1月前
|
数据采集 数据安全/隐私保护 C++
通过C++和libcurl下载网易云音乐音频文件的5个简单步骤
本文将介绍如何通过C和libcurl库下载网易云音乐的音频文件。我们将通过5个简单步骤完成这个任务,同时会使用爬虫代理IP技术来绕过这些网络限制,确保下载的顺利进行。为此,我们将参考爬虫代理的域名、端口、用户名和密码进行设置。网易云音乐作为一个不断发展的音乐平台,其丰富的资源和智能化服务将持续吸引大量用户,而掌握如上所述的下载技巧也将助力开发者更好地利用这些资源。
通过C++和libcurl下载网易云音乐音频文件的5个简单步骤