目录
一、实现cp命令
二、修改程序的配置文件
三、写一个整数/结构体到文件
1.写一个整数到文件
2.写一个结构体到文件
四、写结构体数组到文件
我们学习了文件编程的常用指令以及了解文件编程的基本步骤后,试着来写一些程序实现某些功能。(没有学过的见我的上一篇文章Linux文件编程(打开/创建&写入&读取&光标移动))
一、实现cp命令
我们可以在终端输入“cp 源文件 目标文件”,表示将源文件复制到目标文件(没有则创建)。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
示例:
可以看到一开始是没有demo7.c这个文件的,使用cp指令后创建了demo7.c,并且两个文件内容一样。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -在编写程序之前,我们需要了解main函数的参数,完整的main函数原型为:
#include <stdio.h>int main(int argc, char **argv);
怎么理解这两个参数,拿上面的“cp demo4.c demo7.c”举例,我们假设我们已经把程序写好了,那么在终端上我们会输入“./a.out demo4.c demo7.c”以实现和cp指令同样的操作,那么这个argc就是从第一个文件名开始数,一共有多少个文件,argc就是文件的个数;
argv是一个二级指针,可以理解成指针里的每一项都是一个数组,如果不理解其含义,还是拿上面的举例,argv[0]="./a.out",argv[1]="demo4.c",argv[2]="demo7.c",我自己理解就是将文件名(含双引号)存到argv数组里面。
利用main函数的参数,我们可以把文件的路径传到程序里去,自然就可以通过对文件的读写操作来实现cp指令,讲到这里大家应该都有思路了。
代码实现:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char **argv)
{int fdSrc;//源文件的文件描述符int fdDes;//目标文件的文件描述符char *readBuf=NULL;if(argc != 3){printf("Pararm error\n");exit(-1);//参数不正确就退出程序}fdSrc = open(argv[1],O_RDWR);int size = lseek(fdSrc,0,SEEK_END);//用lseek函数计算源文件的大小lseek(fdSrc,0,SEEK_SET);//在读之前记得将光标复位!!!readBuf=(char *)malloc(sizeof(char)*size + 8);//根据源文件的大小来给readBuf分配内存空间int n_read = read(fdSrc,readBuf,size);//这里不获得返回值也可以fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);//得到目标文件的文件描述符int n_write = write(fdDes,readBuf,strlen(readBuf));//同理read函数close(fdSrc);close(fdDes);return 0;
}
这里有几点要注意的:
1.文件光标位置,在进行读写操作之前,确认光标处于正确的位置。
2.打开文件后必须关闭文件,避免造成数据损坏。
3.在打开目标文件获得其文件描述符时,我们在第二个参数又或上了O_TRUNC,这个参数表示,如果目标文件中原本有内容,会将其全部清除。这样就会避免复制完后,文件本来的内容还存在的情况发生。
(我们不仅能将某个文件拷贝到当前所处文件夹,还能指定文件的绝对路径,拷贝到其他文件夹去)
二、修改程序的配置文件
这里事先创建了TEST.config文件,内容如下
我们想通过程序来修改里面的参数,将LENG改成5。
代码实现:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main(int argc, char **argv)
{int fdSrc;char *readBuf=NULL;if(argc != 2){printf("Pararm error\n");exit(-1);}fdSrc = open(argv[1],O_RDWR);int size = lseek(fdSrc,0,SEEK_END);lseek(fdSrc,0,SEEK_SET);readBuf=(char *)malloc(sizeof(char)*size + 8);int n_read = read(fdSrc,readBuf,size);
/*以上代码和实现cp命令相比,main函数的参数只有两个,也就是说不需要目标文件我们只改变配置文件里面的数据*/char *p = strstr(readBuf,"LENG=");//用strstr函数,会返回'L'的地址。if(p == NULL){printf("not found\n");exit(-1);}p = p+strlen("LENG=");//将指针指向'='后面一位*p = '5';//注意文件里面存的都是字符串,所以要用字符给指针所指向的内存赋值int n_write = write(fdSrc,readBuf,strlen(readBuf));//最后将修改好的Buf写入原先的文件即可close(fdSrc);return 0;
}
这个应用主要是对strstr函数的调用,拿上面代码举例,函数会在readBuf字符串里面找到"LENG="这个字符串,并且返回要找的这个字符串的首地址,就是'L'的地址,要修改等号后面的字符,用strlen计算目标字符串的大小即可。(这种方法只能修改一个字符,如果原本的参数有两位,那么这个程序只能修改等号后面的一位)
三、写一个整数/结构体到文件
我们之前对文件的操作都是基于字符串,如果要向文件写入一个结构体该如何操作?
1.写一个整数到文件
我们先来实现写入一个整数的操作;我们先看write函数的原型
可以看到第二个参数是个无类型的指针,也就是说我们只要传进去的是个地址就可以。
代码实现:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>int main()
{int fd;int data=100;int data2=0;fd = open("./file1",O_RDWR);int n_write = write(fd,&data,sizeof(int));//传入data的地址,长度为int类型的地址长度lseek(fd,0,SEEK_SET);//光标复位int n_read = read(fd,&data2,sizeof(int));printf("read %d\n",data2);//读出来后验证是否成功写入close(fd);return 0;
}
代码还是比较简单的,结果也和我们预期的一样
2.写一个结构体到文件
根据上面的代码,只要稍作改进就可以实现写入结构体到文件
代码实现:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>struct Test{int a;char c;
};int main()
{int fd;struct Test data={100,'a'};struct Test data2;fd = open("./file1",O_RDWR);int n_write = write(fd,&data,sizeof(struct Test)); lseek(fd,0,SEEK_SET);int n_read = read(fd,&data2,sizeof(struct Test));printf("read %d,%c\n",data2.a,data2.c);close(fd);return 0;
}
定义一个结构体,用定义的结构体类型去定义data变量,那么用write和read函数时同样传入的是data的地址,长度为定义的结构体类型的指针的长度。
四、写结构体数组到文件
话不多说,直接上代码
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>struct Test{int a;char c;
};int main()
{int fd;struct Test data[2]={{100,'a'},{101,'b'}};struct Test data2[2];fd = open("./file1",O_RDWR);int n_write = write(fd,&data,sizeof(struct Test)*2);//数组有两个元素,x2就行了 lseek(fd,0,SEEK_SET);int n_read = read(fd,&data2,sizeof(struct Test)*2);printf("read %d,%c\n",data2[0].a,data2[0].c);printf("read %d,%c\n",data2[1].a,data2[1].c);close(fd);return 0;
}
可以看到其实和前面几个代码差不多,只不过在原先的基础上扩展而来。
打印结果:
这些应用程序都是一步一步慢慢扩展来的,该文章也是对c语言的知识做一些巩固和加强,这里面很多操作都涉及到了地址,对地址的概念和对指针的操作还是相当重要的,要熟练的运用指针,才能在程序的道路上畅通无阻。