|
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;iarr2[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函数