有些时候,我们在传输大量的数据时,为了方便比较,最简单的可以做回环测试,我们是知道自己发出去什么数据的,收发的数据完全可以分别存入文件通过cmp来比较是否正确
Windows操作系统中,介绍一种创建数据文件的方法,主要用到三个函数(fopen和fopen_s视作一个):
1.fopen函数
函数名 : fwrite 头文件 : <stdio.h> 功 能: 使用给定的模式mode打开filename所指向的文件 函数原型: FILE *fopen( const char *filename, const char *mode ); 参 数: 参数mode字符串包含了文件访问模式,欲打开的文件路径及文件名,参数 mode 字符串则代表着流形态。mode 有下列几种形态字符串由下图说明: 返回值 : 文件顺利打开后,指向该流的文件指针就会被返回。 如果文件打开失败则返回 NULL,并把错误代码存在error中。 一般而言,打开文件后会做一些文件读取或写入的动作, 若打开文件失败,接下来的读写动作也无法顺利进行,所以一般在 fopen() 后作错误判断及处理。
补充1:
以 x 结尾的模式为独占模式,文件已存在或者无法创建(一般是路径不正确)都会导致 fopen 失败。文件以操作系统支持的独占模式打开。
上述的形态字符串都可以再加一个 b 字符,如 rb、w+b 或 ab+ 等组合,加入 b 字符用来告诉函数库以二进制模式打开文件。如果不加 b,表示默认加了 t,即 rt、wt,其中 t 表示以文本模式打开文件。由 fopen() 所建立的新文件会具有 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666) 权限,此文件权限也会参考umask值。
有些 C编译系统可能不完全提供所有这些功能,有的C版本不用"r+"、“w+”、“a+”,而用"rw"、“wr”、“ar"等,应该注意所用系统的规定。
补充2:
二进制和文本模式的区别
1、在Windows系统中,文本模式下,文件以”\r\n"代表换行。若以文本模式打开文件,并用 fputs 等函数写入换行符"\n"时,函数会自动在"\n"前面加上"\r"。即实际写入文件的是"\r\n"。
2、在类 Unix/Linux 系统中文本模式下,文件以"\n"代表换行。所以 Linux 系统中在文本模式和二进制模式下并无区别。 [1]
补充3:
打开方式总结:
各种打开方式主要有三个方面的区别:
1、打开是否为二进制文件,用“b”标识。
2、读写的方式,有以下几种:只读、只写、读写、追加只写、追加读写这几种方式。
3、对文件是否必 须存在、以及存在时是清空还是追加会有不同的响应。具体判断如图所示
fopen_s函数
fopen_s(&pFile,const char *filename,const char *mode );
VS中、warning C4996: “fopen”被声明为否决的,这是微软的警告,主要是那些都是C库的函数,很多函数内部是不进行参数检测的(包括越界类的),微软担心使用这些会造成内存异常,就改写了一下同样功能的函数,进行了参数的检测。
返回值:成功则返回0,失败会返回
错误条件
EINVAL:无效的参数。
2.fwrite函数
函数名 : fwrite 头文件 : <stdio.h> 功 能: 写内容到流中,从指针ptr开始把n个数据项添加到给定输出流stream,每个数据项的长度为size个字节。 函数原型: size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 参 数: void *ptr 要写入的内容, 是一个指针,对fwrite来说,是要获取数据的地址 int size 这是要被写入的每个元素的大小,以字节为单位 int nitems 这是元素的个数,每个元素的大小为 size 字节 FILE *stream 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。目标文件指针 返回值 : 如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误 用法说明: 写入到文件的哪里与文件的打开模式有关, 如果是w+,则是从file pointer指向的地址开始写,替换掉之后的内容,文件的长度可以不变,stream的位置移动count个数; 如果是a+,则从文件的末尾开始添加,文件长度加大。 fseek对此函数有作用,但是fwrite函数写到用户空间缓冲区,并未同步到文件中,所以修改后要将内存与文件同步可以用fflush(FILE *fp)函数同步。
3.fclose函数
函数名 : fclose 头文件 :<stdio.h> 功 能: 1. 将输出缓冲区内容写到存储设备上 2. 如果不调用fclose,相应地,可能会造成对文件的更改没有被记录到磁盘上,其他进程无法存取 函数原型:int fclose(FILE *stream) 参数: stream-- 这是指向 FILE 对象的指针,该 FILE 对象指定了要被关闭的流。 返回值: 如果流成功关闭,则该方法返回零。如果失败,则返回 EOF。
示例
数据量大的时候,为了保证数据连续常造累加数,但单字节累加是00-ff循环的,一旦整包丢掉,根本无法发现,所以可以8字节累加,以此为例在Windows下创建一个数据文件,入参为创建文件大小,单位为MB(1024*1024)
#include <iostream> #include <fstream> #include "conio.h" #include <iostream> #include <assert.h> #include <stdlib.h> #include <stdio.h> #include <strsafe.h> #include <Windows.h> #include <SetupAPI.h> #include <INITGUID.H> #include <WinIoCtl.h> #include <string> #include <thread> #include <vector> #include <Windows.h> #include <SetupAPI.h> #include <signal.h> #include <INITGUID.H> #include<process.h> #define K_B 1024 #define M_B (K_B * K_B) #define BLK_SIZE (128 * K_B) FILE* file_handle; size_t write_result = 0; int main(int argc,char **argv) { unsigned long long i,cnt; unsigned long long* compareptr, ptrcnt = 0; unsigned long long int total_size = 1000 * M_B; unsigned char *buffer; buffer = (unsigned char*)malloc(BLK_SIZE + K_B); if (argc < 2) printf("usage: %s x_MB\r\n",argv[0]); if (argv[1]) total_size = ((unsigned long long)atoi(argv[1])) * M_B; if (fopen_s(&file_handle, "file_test.bin", "w+b") != 0) { file_handle = NULL; printf("fopen_s failed,errno = %d\r\n",GetLastError()); return -1; } printf("total_size =%llu,total_size / BLK_SIZE = %d\r\n", total_size, total_size / BLK_SIZE); for (cnt = 0; cnt < total_size / BLK_SIZE; cnt++) { compareptr = (unsigned long long*)buffer; for (i = 0; i < BLK_SIZE; i = i + sizeof(unsigned long long)) { ptrcnt++; *compareptr = ptrcnt; compareptr++; } if (file_handle) { write_result = fwrite(buffer, BLK_SIZE, 1, file_handle); if (write_result != 1) { printf("ERROR write_result \n"); } } } if (file_handle) fclose(file_handle); file_handle = NULL; if (buffer) { free(buffer); buffer = NULL; } return 0; }