linux中一切皆文件 Linux 系统中,把一切都看做是文件, 当进程打开现有文件或创建新文件时,内核向进程返回一个文件描述符, 文件描述符就是 内核为了高效 管理已被打开的文件所创建的 索引(0,1,2,...), 用来指向被打开的文件, 通过文件描述符 执行I/O系统调用 文件描述符、文件、进程间的关系 每个文件描述符对应一个打开的文件; 同一文件可以被相同/不同的进程多次打开,每打开一次,都会建立一个文件描述符 不同的文件描述符可能指向同一个文件 父子进程同时打开一个文件 #include <stdio.h> #include <sys/wait.h> int main(){ const char* pathname = "/tmp/a.log"; int f1 = open(pathname); int rc=fork(); if(rc==0){ int f2 = open(pathname); printf("child file index:%d\n",f2); close(f2); }else{ printf("father file index:%d\n",f1); close(f1); wait(NULL); } return 0; } 输出: father file index:3 child file index:4 从3开始向后排列,0,1,2被STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO占用 |
有两套API linux 内核:open,read,write C API: fopen,fread,fwrite fread相比read增加了缓冲功能, 后台还是调用的read,只是减少了与内核交互的次数 |
C目录或文件是否存在 #include <stdio.h> #include <sys/stat.h> #include <stdbool.h> //判断文件或目录是否存在 bool exists(const char* filepath){ struct stat st; if (stat(filepath, &st) == 0) { return 1; } return 0; } int main(){ const char* filename = "/tmp/need2"; // 要获取创建时间的文件名 bool res = exists(filename); if(res){ printf("文件存在\n"); }else{ printf("文件不存在\n"); } return 0; } |
目录还是文件判断 #include <stdio.h> #include <dirent.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> int main(int argc, char const *argv[]) { char const*path = argv[1]; struct stat fil_info; stat(path, &fil_info); if(S_ISDIR(fil_info.st_mode)){ printf("dir\n"); } if(S_ISREG(fil_info.st_mode)){ printf("file\n"); } return 0; } |
遍历 #include <stdio.h> #include <dirent.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> int show_file(const char* path){ struct stat fil_info; /*获取文件信息,把信息放到s_buf中*/ stat(path, &fil_info); if(S_ISDIR(fil_info.st_mode)) { printf("[%s] it is a dir\n",path); struct dirent *filename; DIR *dp = opendir(path); /*readdir()必须循环调用,要读完整个目录的文件,readdir才会返回NULL 若未读完,就让他循环*/ while(filename = readdir(dp)) { /*判断一个文件是目录还是一个普通文件*/ char file_path[200]; bzero(file_path,200); strcat(file_path,path); strcat(file_path,"/"); strcat(file_path,filename->d_name); /*获取文件信息,把信息放到fil_info中*/ stat(file_path,&fil_info); /*判断是否目录*/ if(S_ISDIR(fil_info.st_mode)) { printf("[%s] is a dir\n",file_path); } /*判断是否为普通文件*/ if(S_ISREG(fil_info.st_mode)) { printf("[%s] is a regular file\n",file_path); } } }else if(S_ISREG(fil_info.st_mode)) { printf("[%s] is a regular file\n",path); return 0; } return 0; } int main(int argc, char const *argv[]) { char const*path = argv[1]; show_file(path); return 0; } #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> void tobin(int n){ int arr[32] = { 0 };//int 型有32个字节 int i = 0; while (n > 0) { arr[i] = n % 2; ++i; n /= 2; } int k = 0; for (k = i-1; k >= 0; k--) //逆序输出 { printf("%d", arr[k]); } } int main() { char* fileName = "/tmp/a.log"; struct stat buf; int result; printf("S_IFDIR:%d\n",S_IFDIR); //S_IFDIR:16384 printf("buf.st_mode:%d\n",buf.st_mode); //buf.st_mode:17407 printf("S_IFDIR & buf.st_mode:%d\n",S_IFDIR & buf.st_mode); //S_IFDIR & buf.st_mode:16384 printf("S_IFREG:%d\n",S_IFREG); // S_IFREG:32768 printf("S_IFREG & buf.st_mode:%d\n",S_IFREG & buf.st_mode); //S_IFREG & buf.st_mode:0 tobin(S_IFDIR); //0100000000000000 printf("\n"); tobin(buf.st_mode);//0100001111111111 printf("\n"); tobin(S_IFREG); //1000000000000000 printf("\n"); result = stat(fileName, &buf); if(S_IFDIR & buf.st_mode){ printf("folder\n"); }else if(S_IFREG & buf.st_mode){ printf("file\n"); } return 0; } |
C读取目录下文件 #include <sys/types.h> #include <dirent.h> #include <stdio.h> #include <string.h> #include <time.h> //读取文件列表 void read_dir_files(char *path) { //打开目录是一瞬间的 DIR *dir = opendir(path);//打开目录文件 printf("open dir %s\n","----"); struct dirent *entry; int count = 0; // 不会递归读取子目录 while((entry = readdir(dir))!=0) { //d_name是文件名称,包含后缀,不包含父目录路径, if(strstr(entry->d_name,".txt")) { printf("txt file: %s\n", entry->d_name); }else{ printf("%s\n", entry->d_name); } count++; printf("read file count %d\n",count); } closedir(dir); } int main(){ time_t start,end; // 返回从1970年1月1日00:00:00到现在经过的秒数 start = time(NULL); char *file_dir = "/MTCNN_MY/data/data_tmp/MTCNN/24/positive"; read_dir_files(file_dir); end = time(NULL); // 55459张图片, time = 22.000000 printf("time = %f\n", difftime(end, start)); return 0; } 这里读取目录是流式的,即读取一个目录下的文件,就可以获取这个文件的名称 不是一次性读取所有文件,然后再从第一个文件开始告诉你它的名称是什么 当一个目录下的文件数量万级以上时,这二者差别很大 输出使用了流,IO是共用的,是共享资源,谁有需求谁就可以用一下, 是共享资源它就少,你用的时候刚好有别的程序也在用,那么你就得等待一下 所以输出并不是从第一个循环就有的 跟红绿灯下人群过马路类似,积累一波缓冲输出一下 |
常用文件读写标识 w+ 可读可写,写时覆盖 a+ 可读可写,写时追加 r 读文件,文件若不存在直接报错 b 二进制文件 |
fgetc:一个字符一个字符地读
#include <stdio.h> int main(void){ int ch; FILE *fp; char fname[FILENAME_MAX]; printf("文件名:"); scanf("%s", fname); if((fp = fopen(fname, "r")) == NULL){ printf("文件打开失败。\n"); } else { while ((ch = fgetc(fp)) != EOF){ putchar(ch); } fclose(fp); } return 0; } int fgetc(FILE *stream); 从stream指向的输入流(若存在)中读取unsigned char型的下一个字符的值,并将它转换为int型, 然后,若定义了流的文件位置指示符,则将其向前移动。 若在流中检查到文件末尾,则设置该流的文件结果指示符并返回EOF。
C一次读取文件所有内容
#include <stdio.h> #include <stdlib.h> #include <string.h> char* readAll(const char* filename) { char* data; FILE* fp = fopen(filename, "r"); fseek(fp, 0, SEEK_END); int num_int = (int)ftell(fp); data = (char*)malloc(num_int * sizeof(char)); memset(data, 0, num_int); fseek(fp, 0, SEEK_SET); int size_int = sizeof(int); fread(data, size_int, num_int, fp); fclose(fp); return data; } int main() { printf("%s", readAll("/tmp/a.log")); return 0; }
数字,字符串读写
#include <stdio.h> int main() { FILE *fp = NULL; fp = fopen("/tmp/a.log", "w+"); // w+ 表示可读可写 fprintf(fp, "%d: ",1); // 格式化输入,要输入什么类型先指定格式 fprintf(fp, "每天 学习 五分钟\n"); // 不指定默认为字符串 fputs("2: 每天 运动 半小时\n", fp); // 专写字符串 fclose(fp); char buff[255]; fp = fopen("/tmp/a.log", "r"); fscanf(fp, "%s", buff); //遇到空格或换行符时,停止读取 printf("%s\n", buff ); //1: fgets(buff, 255, (FILE*)fp); //读一行或255个字符 printf("%s\n", buff ); // 每天 学习 五分钟 fgets(buff, 255, (FILE*)fp); printf("3: %s\n", buff ); //2: 每天 运动 半小时 fclose(fp); }
带缓存的字节读写
以f开头表示使用缓冲 fwrite(开始地址,一次写多少个字节,写多少次,文件句柄) fread(开始地址,一次读多少个字节,读多少次,文件句柄) 一次读写多少个字节,读写多少次都是正整数, 定义一个新类型size_t ,表示无符号整形 由于读写N次,需要用到数组结构, 数组元素数据类型占的字节数 是第二个参数“一次读写多少个字节”的值 数组的长度,就是第三个参数“读写多少次”的值 数组的首地址,就是开始地址 数组在内存中以字节连接存储, fwrite的意思就是将数组对应的字节从内存原封不动地搬到文件里, fread是fwrite的逆向操作,原来是从内存到文件,现在就从文件返回到内存, 原来的数组放的是整数,返回后还是整数,原来放的是结构体,返回后还是原来的结构体, 由于高级语言存储的最小单位就是字节, 所以,就没有 fwrite/fread 不能存取的,一切数据就可以使用它们保存/加载
重新认识文件
这里指计算机中的虚拟文件系统, 文件的内容是连续的,底层都是以二进制存储,这一点是不是像数组? 只是在文件看来,没有数据结构一说,你一次存多少个字节进去,完全看你的业务需求 并不会像数组一样要求所有数据类型一致,即底层每个类型的字节数一致以方便数组操作 可以字母,汉字,英文单词混写,至于具体什么含义,怎么断句,文件并不管这个 另一个与数组不同的是,文件是可以写入磁盘的,从这一点看,文件更像是可落盘的数组, 文件还可当作缓冲使用,数组都在内存里, 你需要的数据可以放一个定长的数组,超过长度的部分可以写入文件, 即通过 数组+文件 可控制程序使用内存的多少 在C中,复杂的数据类型,比如文件FILE类型,是一个结构体, 它有一个指针属性-当前读取地址,指向一个地址, 初始化为文件字节的开始地址,每读部分字节,当前读取地址就随之变动, 永远指向当前读到的字节,直到没有字节可读,即文件结束 文件可以很大,但磁盘上未必会有一片连续的地址, 文件可以利用多个磁盘碎片,所以一个文件可能存储在磁盘上的多个位置
rewind重定向:将文件指针重新指向文件开头
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 3 int main(){ int a[N]={1,2,3}, b[N]; int i, size = sizeof(int); FILE *fp; // r是打开存在的文件,若文件不存在则返回NULL;b表示二进制,w表示只写,w+表示写+读 if( (fp=fopen("/tmp/a.txt", "wb+")) == NULL ){ //以二进制方式打开一个文本文件 puts("open file error!"); exit(0); } //将数组a的内容写入到文件 int la = sizeof(a)/sizeof(a[0]); printf("arr a size:%d\n",la); fwrite(a, size, N, fp); //定位到文件开头,否则后面的fread将会从文件尾部开始读取字节 rewind(fp); fread(b, size, N, fp); for(i=0; i<N; i++){ printf("%d ", b[i]); } printf("\n"); fclose(fp); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <stdbool.h> //判断文件或目录是否存在 bool exists(const char* filepath){ struct stat st; if (stat(filepath, &st) == 0) { return 1; } return 0; } void tmp(){ FILE *source_file, *destination_file, *destination_int; char buffer[1024], destination_buffer[1024]; size_t bytes_read, bytes_written; // 打开源文件和目标文件 source_file = fopen("aa.txt", "r"); destination_file = fopen("a22.txt", "wb"); int i; // 按字节读取源文件并写入目标文件 while ((bytes_read = fread(buffer, 1, sizeof(buffer), source_file)) > 0) { printf("bytes_read:%s\n",buffer); fwrite(buffer, 1, bytes_read, destination_file); } // 关闭文件 fclose(source_file); fclose(destination_file); } int main() { tmp(); return 0; }
读取结构体数组:一次读取指定的字节数
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 3 typedef char string[30]; struct Students { int student_id; // 4 bytes string student_name;// 32 bytes float score; // 4 bytes }; int main(){ struct Students students[N] , b[N]; struct Students st1; st1.student_id = 1001; strcpy(st1.student_name,"李秋水"); st1.score = 73; students[0] = st1; int i, size = sizeof(st1); printf("student1 size:%d\n",size); // student1 size:40 struct Students st2; st2.student_id = 1002; strcpy(st2.student_name,"韩立"); st2.score = 74; students[1] = st2; struct Students st3; st3.student_id = 1003; strcpy(st3.student_name,"张无忌"); st3.score = 75; students[2] = st3; FILE *fp; // r是打开存在的文件,若文件不存在则返回NULL;b表示二进制,w表示只写,w+表示写+读 if( (fp=fopen("/tmp/a.txt", "wb+")) == NULL ){ //以二进制方式打开一个文本文件 puts("open file error!"); exit(0); } //将数组a的内容写入到文件 int la = sizeof(students)/sizeof(students[0]); printf("arr a size:%d\n",la); fwrite(students, size, N, fp); //定位到文件开头,否则后面的fread将会从文件尾部开始读取字节 rewind(fp); fread(b, size, N, fp); for(i=0; i<N; i++){ printf("%s \n", b[i].student_name); } printf("\n"); fclose(fp); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 3 typedef char string[30]; struct Students { int student_id; // 4 bytes string student_name;// 32 bytes float score; // 4 bytes }; int main(){ struct Students students[N] , b[N+1]; struct Students st1; st1.student_id = 1001; strcpy(st1.student_name,"李秋水"); st1.score = 73; students[0] = st1; int i, size = sizeof(st1); printf("student1 size:%d\n",size); // student1 size:40 struct Students st2; st2.student_id = 1002; strcpy(st2.student_name,"韩立"); st2.score = 74; students[1] = st2; struct Students st3; st3.student_id = 1003; strcpy(st3.student_name,"张无忌"); st3.score = 75; students[2] = st3; FILE *fp; // r是打开存在的文件,若文件不存在则返回NULL;b表示二进制,w表示只写,w+表示写+读 if( (fp=fopen("/tmp/a.txt", "wb+")) == NULL ){ //以二进制方式打开一个文本文件 puts("open file error!"); exit(0); } //将数组a的内容写入到文件 int la = sizeof(students)/sizeof(students[0]); printf("arr a size:%d\n",la); fwrite(students, size, N, fp); //定位到文件开头,否则后面的fread将会从文件尾部开始读取字节 rewind(fp); fread(b, size, N+1, fp); printf("----------原数据块------------------------------\n"); for(i=0; i<N+1; i++){ printf("%s \n", b[i].student_name); } // 追加 struct Students st5; st5.student_id = 1007; strcpy(st5.student_name,"江澄"); st5.score = 82; fwrite(&st5, size, 1, fp); //定位到文件开头,否则后面的fread将会从文件尾部开始读取字节 rewind(fp); // 覆盖 struct Students st7; st7.student_id = 1007; strcpy(st7.student_name,"南宫婉"); st7.score = 86; fwrite(&st7, size, 1, fp); //定位到文件开头,否则后面的fread将会从文件尾部开始读取字节 rewind(fp); fread(b, size, N+1, fp); printf("----------修改(覆盖,追加)后的数据块------------------------\n"); for(i=0; i<N+1; i++){ printf("%s \n", b[i].student_name); } printf("\n"); printf("----------局部读取,定位第2个块结束,第3个数据块开始的位置,即读取第3个数据块------------\n"); fseek(fp,size*(3-1),SEEK_SET); fread(b, size, 1, fp); printf("%s \n", b[0].student_name); fclose(fp); return 0; } $ gcc f1.c $ ./a.out student1 size:40 arr a size:3 ----------原数据块------------------------------ 李秋水 韩立 张无忌 ----------修改(覆盖,追加)后的数据块------------------------ 南宫婉 韩立 张无忌 江澄 ----------局部读取,定位第2个块结束,第3个数据块开始的位置,即读取第3个数据块------------ 张无忌
tmpnam代码示例
#include <stdio.h> int main () { // 临时文件,程序运行结束就自己消失 // printf("文件名长度:%d,最多可创建临时文件个数:%d\n",L_tmpnam,TMP_MAX); char buffer[L_tmpnam]; char *ptr; tmpnam(buffer); printf("Temporary name 1: %s\n", buffer); puts(buffer); ptr = tmpnam(NULL); printf("Temporary name 2: %s\n", ptr); return(0); } $ gcc t.c /tmp/cc35QRUw.o: In function `main': t.c:(.text+0x29): warning: the use of `tmpnam' is dangerous, better use `mkstemp' $ ./a.out 文件名长度:20,最多可创建临时文件个数:238328 Temporary name 1: /tmp/file5h3eVn /tmp/file5h3eVn Temporary name 2: /tmp/fileTog9xu $ ./a.out 文件名长度:20,最多可创建临时文件个数:238328 Temporary name 1: /tmp/fileqOMwTG /tmp/fileqOMwTG Temporary name 2: /tmp/file0nzEu5
临时文件及格式
临时 体现在程序运行结束后,文件自动删除; 每次运行生成的文件名称随机 格式 file+6位16进制,位于系统的临时目录下,linux的临时目录就是/tmp目录 TMP_MAX 最多可创建临时文件的个数 L_tmpnam 用于存放临时文件名称的数组长度, 如果为NULL,则名称做为返回值返回
int mkstemp(char *template)
mkstemp函数创建一个文件并打开,权限0600。 函数返回一个文件描述符,如果执行失败返回-1。 unlink函数删除文件的目录入口,但还可以在代码中通过文件名称对文件进行读写操作 程序退出,临时文件自动删除
#include <stdio.h> int main(void) { int fd; char temp_file_path[]="/tmp/tmp_XXXXXX"; if((fd=mkstemp(temp_file_path))==-1) { printf("Creat temp file faile./n"); }else{ printf("temp file path:%s\n",temp_file_path); unlink(temp_file_path); //----------------------------- //这里可对临时文件进行读写操作 //----------------------------- close(fd); } return 0; }
$ gcc t.c $ ./a.out temp file path:/tmp/tmp_LqlCqW $ ./a.out temp file path:/tmp/tmp_AHrteC
C 写CSV
#include <stdio.h> #include <stdlib.h> int main() { char * file_name = "tmp.csv"; FILE *fp = fopen(file_name, "w+"); if (fp == NULL) { fprintf(stderr, "open %s failed.\n",file_name); exit(EXIT_FAILURE); } fprintf(fp, "tid,card_num,card_time\n"); fprintf(fp, "1,62208032347824361274,2023-10-11 14:18:12\n"); int id = 2; char *card_num = "62202232347824361435322"; char *card_time = "2023-10-12 11:18:12"; fprintf(fp, "%d,%s,%s\n", id, card_num, card_time); fclose(fp); return 0; }
C 读CSV
#include <stdio.h> #include <stdlib.h> #include <string.h> void write_csv(){ char * file_name = "tmp.csv"; FILE *fp = fopen(file_name, "w+"); if (fp == NULL) { fprintf(stderr, "open %s failed.\n",file_name); exit(EXIT_FAILURE); } fprintf(fp, "tid,card_num,card_time\n"); fprintf(fp, "1,62208032347824361274,2023-10-11 14:18:12\n"); int id = 2; char *card_num = "62202232347824361435322"; char *card_time = "2023-10-12 11:18:12"; fprintf(fp, "%d,%s,%s\n", id, card_num, card_time); fclose(fp); } void read_csv(char *file_name){ FILE *fp = fopen(file_name, "r"); if (fp == NULL) { fprintf(stderr, "open %s failed.\n",file_name); exit(EXIT_FAILURE); } int max_size=6000; char row[max_size]; char *val; char* tmp =NULL; while (fgets(row, max_size, fp) != NULL) { printf("Row: %s", row); int i = 0; val = strtok_r(row, ",", &tmp); while (val != NULL) { i++; printf("col %d: %s\n", i,val); val = strtok_r(NULL, ",",&tmp); } } fclose(fp); } int main() { char* file_name = "tmp.csv"; read_csv(file_name); return 0; }
C读CSV到指针数组
#include <stdio.h> #include <stdlib.h> #include <string.h> void ss_arr(char* row, char** res){ char* tmp=NULL; char* val = strtok_r(row, ",", &tmp); int i=0; while (val != NULL) { res[i] = val; val = strtok_r(NULL, ",",&tmp); i++; } } int main() { char row[] = "Row: 2,62202232347824361435322,2023-10-12 11:18:12"; int max_size=100; //指针数组,每个元素都是一个指针 char* res[max_size]; ss_arr(row,res); int i; for(i=0;i<3;i++){ printf("%s\n",res[i]); } return 0; }
Row: 2 62202232347824361435322 2023-10-12 11:18:12
#include <stdio.h> #include <stdlib.h> #include <string.h> void ss_arr(char* row, char** res){ char* tmp=NULL; char* val = strtok_r(row, ",", &tmp); int i=0; while (val != NULL) { res[i] = val; val = strtok_r(NULL, ",",&tmp); i++; } } //max_col_size:拆分成多少个元素 void deal(char* row,int max_col_size){ char* res[max_col_size]; ss_arr(row,res); int i; for(i=0;i<max_col_size;i++){ printf("%s\n",res[i]); } } void read_csv(char *file_name, void(*func)(char*,int),int max_col_size){ FILE *fp = fopen(file_name, "r"); if (fp == NULL) { fprintf(stderr, "open %s failed.\n",file_name); exit(EXIT_FAILURE); } int max_size=6000; char row[max_size]; char *val; char* tmp =NULL; while (fgets(row, max_size, fp) != NULL) { func(row,max_col_size); } fclose(fp); } int main() { char* file_name = "tmp.csv"; read_csv(file_name,deal,3); return 0; }
tid card_num card_time 1 62208032347824361274 2023-10-11 14:18:12 2 62202232347824361435322 2023-10-12 11:18:12
10022,62284800003,2022-12-19 19:10:20,1,6,1671495020.0,"10009,10008,10007,10006","2022-11-19 14:10:20,2022-11-19 17:10:20,2022-11-19 19:10:10,2022-11-19 19:10:20" 10024,62284800003,2022-12-21 19:10:20,1,6,1671667820.0,"10009,10008,10007,10006","2022-11-19 14:10:20,2022-11-19 17:10:20,2022-11-19 19:10:10,2022-11-19 19:10:20" 本例读取的是这样格式的CSV 最后两个列要解析到两个数据中,前面所有列解析到一个数组中 以逗号分隔
主体思路
先以逗号分隔到一个数组 然后从第1个双引号与第2个双引号是一个数组 第3个双引号与第4个双引号是一个数组
#include <stdio.h> #include <stdlib.h> #include <string.h> //按逗号拆分一行文本为数组,row必须是数组 void ss_arr(char** res, char* row){ char* tmp=NULL; char* val = strtok_r(row, ",", &tmp); int i=0; while (val != NULL) { res[i] = val; val = strtok_r(NULL, ",",&tmp); i++; } } #define MAX_ARR_LEN 108 #define MAX_COL_NUM 7 //最后两个字段列是数组 struct CsvRow { char* arr[MAX_COL_NUM]; char* arr2[MAX_ARR_LEN]; char* arr3[MAX_ARR_LEN]; }; typedef struct CsvRow CRow; void row_parser(CRow* cr, char* str){ char* arr[MAX_ARR_LEN]; int i; for(i=0;iarr[i]=NULL; //除最后两个字段外的所有字段 } for(i=0;i arr2[i]=NULL;//id数组 cr->arr3[i]=NULL;//时间数组 } ss_arr(arr,str); int arr_flag = 0; int n =0; int m =0; int h=0; int begin = 0;//数据部分标识,在CSV中排好的位置,两个数组相邻 for(i=0;arr[i]!=0;i++){ int tmp_size = strlen(arr[i])-1; if (arr[i][0]=='\"' && arr[i][tmp_size] !='\"'){//最后两个数组中间首部 begin=1; if(arr_flag==0){ cr->arr2[n++] = &(arr[i])[1]; }else if (arr_flag==1){ cr->arr3[m++] = &(arr[i])[1]; } }else if (arr[i][0]!='\"' && arr[i][tmp_size] =='\"' && begin>0){//最后两个数组中间尾部 arr[i][tmp_size] = '\0'; if(arr_flag==0){ cr->arr2[n++] = arr[i]; }else if (arr_flag==1){ cr->arr3[m++] = arr[i]; } arr_flag++; }else if (begin>0){//最后两个数组中间部分 if(arr_flag==0){ cr->arr2[n++] = arr[i]; }else if (arr_flag==1){ cr->arr3[m++] = arr[i]; } }else{//除最后两个数组外的所有字段 cr->arr[h++] = arr[i]; } } } int main(void) { char str[2000]="10024,62284800003,2022-12-21 19:10:20,1,6,1671667820.0,\"10009,10008,10007,10006\",\"2022-11-19 14:10:20,2022-11-19 17:10:20,2022-11-19 19:10:10,2022-11-19 19:10:20\""; CRow cr; row_parser(&cr,str); int j; for(j=0;cr.arr[j]!=0;j++){ printf("arr[%d]=%s\n",j,cr.arr[j]); } for(j=0;cr.arr2[j]!=0;j++){ printf("arr2[%d]=%s\n",j,cr.arr2[j]); } for(j=0;cr.arr3[j]!=0;j++){ printf("arr3[%d]=%s\n",j,cr.arr3[j]); } }
$ gcc c.c $ ./a.out arr[0]=10024 arr[1]=62284800003 arr[2]=2022-12-21 19:10:20 arr[3]=1 arr[4]=6 arr[5]=1671667820.0 arr2[0]=10009 arr2[1]=10008 arr2[2]=10007 arr2[3]=10006 arr3[0]=2022-11-19 14:10:20 arr3[1]=2022-11-19 17:10:20 arr3[2]=2022-11-19 19:10:10 arr3[3]=2022-11-19 19:10:20
补充说明
char* arr[MAX_COL_NUM]; 字符串 指针数组,每个元素都是一个字符指针,指向一个 不定长 的字符串的首地址 所以,无法通过malloc直接分配一个定长的地址 当然了,可以根据业务含义,取一个最大值, 比如这里的最大值就是时间的长度
C 自定义写日志:超过MAX_LOG_SIZE被重置,带开关
#define MAX_LOG_SIZE 1048576 // 1M int log_open = 1; //超过MAX_LOG_SIZE被重置 int lg(const char* LOG_FILE, bool isopen, char* line) { // printf("open log:%d\n",isopen); if (!isopen){ return -1; } FILE *fp; size_t len; long pos; // 打开日志文件,如果文件不存在则创建 fp = fopen(LOG_FILE, "a+"); if (fp == NULL) { printf("Failed to open log file.\n"); exit(1); } // 检查日志文件大小,如果超过1M则重写 fseek(fp, 0L, SEEK_END); pos = ftell(fp); if (pos > MAX_LOG_SIZE) { rewind(fp); // 把文件指针移到文件开头 fp = freopen(LOG_FILE, "w", fp); // 重新打开文件,清空内容 printf("日志文件%s开始重写...\n",LOG_FILE); if (fp == NULL) { printf("Failed to reopen log file.\n"); exit(1); } } // 写入日志 len = strlen(line)+50; char tmp[len] ; char currentTime[20]; time_t rawtime; struct tm * timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); strftime(currentTime, 20, "%Y-%m-%d %H:%M:%S", timeinfo); sprintf(tmp,"[%s]:%s\n",currentTime,line); fwrite(tmp, 1, strlen(tmp), fp); // 关闭文件 fclose(fp); return 0; }
其他文件引用时,可能会需要加上extern
extern int lg(const char* LOG_FILE, bool isopen, char* line); extern int log_open;
C 自定义写日志:超过MAX_LOG_SIZE被重置
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define MAX_LOG_SIZE 1048576 // 1M //超过MAX_LOG_SIZE被重置 int lg(const char* LOG_FILE, char* line) { FILE *fp; size_t len; long pos; // 打开日志文件,如果文件不存在则创建 fp = fopen(LOG_FILE, "a+"); if (fp == NULL) { printf("Failed to open log file.\n"); exit(1); } // 检查日志文件大小,如果超过1M则重写 fseek(fp, 0L, SEEK_END); pos = ftell(fp); if (pos > MAX_LOG_SIZE) { rewind(fp); // 把文件指针移到文件开头 fp = freopen(LOG_FILE, "w", fp); // 重新打开文件,清空内容 printf("日志文件%s开始重写...\n",LOG_FILE); if (fp == NULL) { printf("Failed to reopen log file.\n"); exit(1); } } // 写入日志 len = strlen(line)+50; char tmp[len] ; char currentTime[20]; time_t rawtime; struct tm * timeinfo; time(&rawtime); timeinfo = localtime(&rawtime); strftime(currentTime, 20, "%Y-%m-%d %H:%M:%S", timeinfo); sprintf(tmp,"[%s]:%s\n",currentTime,line); fwrite(tmp, 1, strlen(tmp), fp); // 关闭文件 fclose(fp); return 0; } int main() { char line[1024] = "a一\n"; lg("log.txt",line); char* line2 = "b三"; lg("log.txt",line2); int i ; for(i=0;i < 1000000;i++){ lg("log.txt","测试是否会重置-----------------------------"); } return 0; }
如果将一个文件按字节转int,再从int转字节写入文件,可以吗? 对于txt完全没问题 对于部分gcc编辑出来的可执行文件也没问题 ELF(Executable and Linking Format)是一种对象文件的格式, 在linux平台上被广泛接受,作为缺省的二进制文件格式来使用。 $ file librust2py.so librust2py.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=85b35abbcf194ab73a8fb360cade3eb14ce56623, not stripped 对于.so库文件有问题,目的在于防篡改...
int fseek ( FILE * stream, long offset, int origin );
从指定位置origin移到文件指针offset个字节 origin有三种,分别为: SEEK_CUR - 文件指针当前的位置 SEEK_END - 文件末尾的位置,0或负数 SEEK_SET - 文件开始的位置,0或正数
ssize_t read( int fd, void *buf, size_t nbyte) :将数据从外设上经过内核读到用户空间
size_t nbyte (size_t为无符号整型) 一次从buf中读取nbyte个字节到描述符为fd的文件中, 对于大文件来说,该值设置大一点可以减少与内核交互次数,进而提高整体速度 返回值 (ssize_t为有符号整型) 大于0,读取字节数, 等于0,表示读到文件结束. 小于0,读取失败. EINTR-中断, ECONNREST-网络问题.
#include <stdio.h> #include <stdlib.h> #include <sys/stat.h> int main(){ // stat结构体 struct stat fil_info; // stat函数 stat("/tmp",&fil_info); //0-成功,-1-失败 if((stat("/tmp",&fil_info))==0){ //mode_t st_mode,文件类型及存储权限 printf("st_mode:%d\n",fil_info.st_mode); //st_mode:17407 //ino_t st_ino,文件的序列号 printf("st_ino:%ld\n",fil_info.st_ino); //st_ino:2359297 //off_t st_size,byte printf("st_size:%ld\n",fil_info.st_size);//st_size:4096 //time_t st_mtime,最后被修改时间 printf("st_mtime:%ld\n",fil_info.st_mtime); //st_mtime:1689228870 //time_t st_ctime,最后状态改变时间 printf("st_ctime:%ld\n",fil_info.st_ctime); //st_ctime:1689228870 } return 0; }
C语言 读取文件内容 文件描述符(通俗易懂) C语言文件操作 read和write函数的使用 C语言中write函数