文章目录
Linux文件开发
查看Linux用户手册
man + 关键字
man 2 open
打开用户手册中的第2页的open函数那一章
文件的打开与创建open函数
包含头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
函数描述
file descriptor
文件描述符
call
调用
给一个文件的路径,返回一个文件描述符,它是一个小的非负整数用在后续的系统调用中。文件打开成功返回非负整数,打开失败返回-1
查看文件权限
ls -l
rw可读写;x可执行
open函数中的mode权限:
可读可写就是0400+0200=0600
用法
- 正常打开一个文件:新建一个file1文件,在当前文件夹内新建file1.c输入如下代码
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5
6 int main()
7 {
8 int fd;
9 fd = open("./file1",O_RDWR);
10 printf("fd = %d\n",fd);
11 return 0;
12 }
//fd = 3
- 如果文件不存在则创建文件并打开:删除file1文件,在当前文件夹内新建file1.c输入如下代码
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5
6 int main()
7 {
8 int fd;
9 fd = open("./file1",O_RDWR);
10 if(fd = -1)
11 {
12 printf("file doesn't exist!\n");
13 fd = open("./file1",O_RDWR|O_CREAT,00600);
14 if(fd > 0)
15 {
16 printf("create file successfully!\n");
17 }
18 }
19 printf("fd = %d\n",fd);
20 return 0;
21 }
//file doesn't exist!
//create file successfully!
//fd = 3
文件写入操作编程write函数
write函数描述
write函数从buf缓冲区向文件描述符fd指代的文件中写入count大小的数据。
如果写入成功,返回写入数据的大小(0代表没东西被写入),-1表示有错误。
包含头文件
#include <unistd.h>
close函数
写入文件内容后用close函数关闭文件
用法
如果file1文件不存在则先创建,再写入12345678901234567890,最后关闭文件file1
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <string.h>
7
8 int main()
9 {
10 int fd;
11 fd = open("./file1",O_RDWR);
12 if(fd = -1)
13 {
14 printf("file doesn't exist!\n");
15 fd = open("./file1",O_RDWR|O_CREAT,00600);
16 if(fd > 0)
17 {
18 printf("create file successfully!\n");
19 }
20 }
21 printf("open file successfully!\n",fd);
22 char *buf = "12345678901234567890";
23 write(fd,buf,strlen(buf)*sizeof(char));
24 close(fd);
25 return 0;
26 }
文件读取操作read函数
函数描述
函数会从文件描述符fd所在的文件中读取count个字节大小的数据到buf缓冲区内。
读取成功返回读取的字节大小,失败返回-1
包含头文件
#include <unistd.h>
用法
读取写入file1文件的数据,读取时采用重新打开文件让光标定位到数据开头
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <stdlib.h>
8
9 int main()
10 {
11 int fd;
12 fd = open("./file1",O_RDWR);
13 if(fd = -1)
14 {
15 printf("file doesn't exist!\n");
16 fd = open("./file1",O_RDWR|O_CREAT,00600);
17 if(fd > 0)
18 {
19 printf("create file successfully!\n");
20 }
21 }
22 printf("open file successfully!\n",fd);
23 char *buf = "12345678901234567890";
24 int n_write;
25 n_write = write(fd,buf,strlen(buf)*sizeof(char));
26 close(fd);
27 fd = open("./file1",O_RDWR|O_CREAT,00600);
28 if(n_write != -1)
29 {
30 printf("write %d bytes to file1\n",n_write);
31 }
32 int n_read;
33 char *readBuf = (char *)malloc(n_write);
34 n_read = read(fd,readBuf,n_write);
35 printf("read %d bytes,context is:%s\n",n_read,readBuf);
36 return 0;
37 }
文件光标移动操作lseek函数
函数描述
函数是用来重新定位打开的文件的光标的。
SEEK_SET光标在数据头部位置
SEEK_CUR光标在数据当前位置
SEEK_END光标在数据尾部位置
offset设置光标向右偏移字节大小,向左偏移为负数
读取成功返回从文件开始的偏移字节大小,读取失败返回-1
包含头文件
#include <sys/types.h>
#include <unistd.h>
用法
- 打开文件并写入数据后,将光标重新定位至数据头部,读取数据
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <stdlib.h>
8
9 int main()
10 {
11 int fd;
12 fd = open("./file1",O_RDWR);
13 if(fd = -1)
14 {
15 printf("file doesn't exist!\n");
16 fd = open("./file1",O_RDWR|O_CREAT,00600);
17 if(fd > 0)
18 {
19 printf("create file successfully!\n");
20 }
21 }
22 printf("open file successfully!\n",fd);
23 char *buf = "12345678901234567890";
24 int n_write;
25 n_write = write(fd,buf,strlen(buf)*sizeof(char));
26 if(n_write != -1)
27 {
28 printf("write %d bytes to file1\n",n_write);
29 }
30 int n_read;
31 char *readBuf = (char *)malloc(n_write);
32 lseek(fd,-n_write,SEEK_END);
//lseek(fd,0,SEEK_SET); //lseek(fd,-n_write,SEEK_CUR);都可以
33 n_read = read(fd,readBuf,n_write);
34 printf("read %d bytes,context is:%s\n",n_read,readBuf);
35 return 0;
36 }
- 计算文件大小
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <sys/types.h>
5 #include <unistd.h>
6 #include <stdio.h>
7
8 int main()
9 {
10 int fd;
11 fd = open("./file1",O_RDWR);
12 if(fd == -1)
13 {
14 printf("file1 doesn't exist!\n");
15 fd = open("./file1",O_RDWR|O_CREAT,00600);
16 printf("create file1 success!\n");
17 }
18 printf("open file1 success!");
19 int fileSize;
20 fileSize = lseek(fd,0,SEEK_END);
21 printf("file1's size is %d\n",fileSize);
22 return 0;
23 }
因为lseek返回的是从文件开始到光标的偏移字节大小,所以要把光标移动到文件尾部lseek(fd,0,SEEK_END)
文件打开创建补充
O_EXCL参数描述
如果在open函数内同时写了O_CREAT,如果文件存在则打开失败返回-1
O_EXCL参数的用法
如果文件file1存在则提示文件已存在,如果删除file1重新调用程序,则创建文件
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5
6 int main()
7 {
8 int fd;
9 fd = open("./file1",O_RDWR|O_CREAT|O_EXCL,00600);
10 if(fd == -1)
11 {
12 printf("file1 has existed!\n");
13 }
14 return 0;
15 }
O_APPEND参数描述
写入数据时如果首次调用含O_APPEND的open函数则会在文件尾部写入数据
O_APPEND参数的用法
如果用了该参数则在文件尾部写数据,如果没用该参数,写入的新数据会覆盖原来的位置
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <string.h>
7
8 int main()
9 {
10 int fd;
11 fd = open("./file1",O_RDWR|O_APPEND);
12 printf("fd = %d\n",fd);
13 char *buf = "peterpeter";
14 write(fd,buf,strlen(buf)*sizeof(char));
15 close(fd);
16 return 0;
17 }
O_TRUNC参数描述
如果文件中有内容,将其清空再写入新数据。
注意:在open函数里加了该参数,后面就读取不到内容了,因为被清空了
O_TRUNC参数的用法
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <string.h>
7
8 int main()
9 {
10 int fd;
11 fd = open("./file1",O_RDWR|O_TRUNC);
12 printf("fd = %d\n",fd);
13 char *buf = "peterpeter";
14 write(fd,buf,strlen(buf)*sizeof(char));
15 close(fd);
16 return 0;
17 }
creat函数描述
creat函数的用法
在当前路径下创建一个名为file2的文件,可读可写可执行
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4
5 int main()
6 {
7 creat("./file2",S_IRWXU);
8 return 0;
9 }
文件操作原理简述
文件描述符
标准输入和标准输出
文件描述符(0,1,2)宏STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO代表标准输入、标准输出和标准错误。标准输入就是从键盘读取;标准输出就是从控制台输出
1 #include <unistd.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4
5 int main()
6 {
7 char *readBuf = (char *)malloc(10);
8 read(STDIN_FILENO,readBuf,10);
9 write(STDOUT_FILENO,readBuf,10);
10 printf("done!\n");
11 return 0;
12 }
从键盘输入//sdfs
//sdfs
//done!
从键盘读取10个字节到readBuf缓冲区,再从readBuf缓冲区写到控制台10个字节,所以这里都是readBuf
操作文件的步骤
静态文件存在块设备中 -> 调用open -> 在linux内核申请内存(动态内存)用一个数据结构储存 -> 读写 -> 调用close -> linux内核中的动态内存更新块设备中的静态文件
文件操作应用——实现cp命令
main函数的参数
main函数的参数从第一个指令开始
1 #include <stdio.h>
2
3 int main(int argc,char **argv)
4 {
5 printf("number of argc is:%d\n",argc);
6 printf("No.1 param is:%s\n",argv[0]);
7 printf("No.2 param is:%s\n",argv[1]);
8 printf("No.3 param is:%s\n",argv[2]);
9 return 0;
10 }
编程实现
思路:
打开src.c
读src.c中的数据到readBuf
打开/创建des.c
将readBuf写入des.c,如果des.c不存在则创建,如果des.c存在,写入前清空其内容
关闭两个文件
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8
9 int main(int argc,char **argv)
10 {
11 if(argc != 3)
12 {
13 printf("param error!\n");
14 exit(-1);
15 }
16 int fdSrc;
17 fdSrc = open(argv[1],O_RDWR);
18 int fileSize = lseek(fdSrc,0,SEEK_END);
19 lseek(fdSrc,0,SEEK_SET);
20 char *readBuf = (char *)malloc(sizeof(char)*fileSize);
21 read(fdSrc,readBuf,fileSize);
22 int fdDes;
23 fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,00600);
24 write(fdDes,readBuf,strlen(readBuf)*sizeof(char));
25 close(fdSrc);
26 close(fdDes);
27 return 0;
28 }
//gcc mycp.c -o mycp
//./mycp file1 file2
//file1被复制成file2
perror()函数打印错误信息
调用perror函数后程序会自动结束
文件编程应用——修改程序的配置文件
思路:
打开文件
读取文件到readBuf缓冲区
用strstr()查找目标字符串
指针定位到目标数据位置并修改数据
将readBuf写入原文件
关闭文件
以下代码只能修改1位数字
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8
9 int main(int argc,char **argv)
10 {
11 if(argc != 2)
12 {
13 printf("param error!\n");
14 exit(-1);
15 }
16 int fd;
17 fd = open(argv[1],O_RDWR);
18 int fileSize = lseek(fd,0,SEEK_END);
19 lseek(fd,0,SEEK_SET);
20 char *readBuf = (char *)malloc(sizeof(char)*fileSize + 1);
21 read(fd,readBuf,fileSize);
22 char *p = strstr(readBuf,"WIDTH = ");
23 if(p == NULL)
24 {
25 printf("not found!\n");
26 exit(-1);
27 }
28 p = p + strlen("WIDTH = ");
29 *p = '8';
30 /* while(++p != NULL)
31 {
32 if(*p == '\0')
33 {
34 break;
35 }
36 *p = '\0';
37 }*/
38 lseek(fd,0,SEEK_SET);
39 write(fd,readBuf,fileSize);
40 close(fd);
41 return 0;
42 }
//gcc changeConfig.c -o changeConfig
//./changeConfig test.config
WIDTH修改为8
写除了字符串类型到文件
写一个整数到文件
write()和read()函数中的参数类型是const void * 所以不一定要是char * 类型
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdio.h>
6
7 int main()
8 {
9 int fd;
10 fd = open("./file1",O_RDWR);
11 int data = 10;
12 write(fd,&data,sizeof(int));
13 lseek(fd,0,SEEK_SET);
14 int data2;
15 read(fd,&data2,sizeof(int));
16 printf("read:%d\n",data2);
17 close(fd);
18 return 0;
19 }
写一个结构体到文件
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdio.h>
6
7 typedef struct node
8 {
9 int a;
10 char c;
11 }Node;
12
13 int main()
14 {
15 int fd;
16 fd = open("./file1",O_RDWR);
17 Node node1 = {1,'g'};
18 write(fd,&node1,sizeof(Node));
19 lseek(fd,0,SEEK_SET);
20 Node node2;
21 read(fd,&node2,sizeof(Node));
22 printf("read:%d,%c\n",node2.a,node2.c);
23 close(fd);
24 return 0;
25 }
写一个结构体数组到文件
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <stdio.h>
6
7 typedef struct node
8 {
9 int a;
10 char c;
11 }Node;
12
13 int main()
14 {
15 int fd;
16 fd = open("./file1",O_RDWR);
17 Node node1[2] = {
{1,'g'},{2,'h'}};
18 write(fd,&node1,sizeof(Node)*2);
19 lseek(fd,0,SEEK_SET);
20 Node node2[2];
21 read(fd,&node2,sizeof(Node)*2);
22 printf("read:%d,%c\n",node2[0].a,node2[0].c);
23 printf("read:%d,%c\n",node2[1].a,node2[1].c);
24 close(fd);
25 return 0;
26 }
open和fopen的区别
-
来源不同
open是Unix系统调用函数。fopen的C语言库函数。 -
移植性不同
fopen移植性更好,能在更多系统中调用。 -
适用范围不同
fopen用来操作普通文件。open主要用于linux系统。 -
缓冲
fopen是在缓冲区操作文件,效率更高。open是通过用户态和内核态切换操作文件。但现在的机器这点效率忽略不计。
标准C库操作文件
fopen()函数描述
fopen()函数用来打开文件。传入path文件路径,mode打开的文件权限,mode是字符串指针 。权限如第二张图,w+表示不存在就创建文件。成功调用该函数返回FILE的指针,有错返回NULL。
fwrite()和fread()函数描述
fwrite()函数用来向文件写入数据。它从ptr缓冲区获取nmemb数量每个size字节大小的数据写入stream指向的文件流。
fread()函数用来读取数据。它从stream指向的文件流中读取nmemb数量每个size字节大小的数据储存到ptr缓冲区中。
fwrite()和fread()返回成功写入或读取的项目数量,如果调用出错返回很小的项目数量或0。它们的返回值取决于第三个参数nmemb
如果fwrite的nmemb参数写的很大,会将乱码写入目标文件,如下图:
如果fread的nmemb参数写的很大,没有问题
fseek()函数描述
fseek用来操作文件中的光标位置。参数和lseek用法相同。成功调用返回0,失败返回-1。
用法
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 int main()
6 {
7 FILE *fp;
8 fp = fopen("./file1","w+");
9 char *str = "hello world!";
10 int n_write = fwrite(str,sizeof(char),strlen(str),fp);
11 fseek(fp,0,SEEK_SET);
12 char *readBuf = (char *)malloc(20);
13 int n_read = fread(readBuf,sizeof(char),strlen(str),fp);
14 printf("read:%s\n",readBuf);
15 printf("n_write = %d\n",n_write);
16 printf("n_read = %d\n",n_read);
17 return 0;
18 }
//read:hello world!
//n_write = 12
//n_read = 12
如果写入的数据数量大于字符数量,比如fwrite(str,sizeof(char),20,fp);会在file1中多写入其它字符造成错误
写入结构体
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 typedef struct Node
6 {
7 int num;
8 char name;
9 }Node;
10 int main()
11 {
12 Node data1 = {100,'a'};
13 FILE *fp;
14 fp = fopen("./file1","w+");
15 int nwrite = fwrite(&data1,sizeof(Node),1,fp);
16 Node data2;
17 fseek(fp,0,SEEK_SET);
18 int nread = fread(&data2,sizeof(Node),1,fp);
19 printf("read:num = %d\tname = %c\n",data2.num,data2.name);
20 printf("write:%d\tread:%d\n",nwrite,nread);
21 fclose(fp);
22 return 0;
23 }
//read:num = 100 name = a
//write:1 read:1
fputc()函数描述
fputc()函数将参数c强制转换成无符号字符,写入stream文件流
返回被写入的无符号字符强转成整型的整数,失败返回EOF
用法
将字符串写入file1文件中
1 #include <stdio.h>
2 #include <string.h>
3
4 int main()
5 {
6 FILE *fp;
7 fp = fopen("./file1","w+");
8 char *str = "hello world!";
9 int i;
10 int len = strlen(str);
11 int a;
12 for(i = 0; i < len; i++)
13 {
14 a = fputc(*str,fp);
15 str++;
16 printf("fputc = %d\n",a);
17 }
18 fclose(fp);
19 return 0;
20 }
注意这里for循环中要将len提前赋值,因为如果写成i < strlen(str),随着每次循环str++,strlen(str)的值也会随之变化
fgetc()和feof()函数描述
fgetc()函数从stream文件流中读取一个字符,将其转换成无符号字符并强转成整型输出,返回EOF时有错误<