七.文件操作原理
1.文件描述符
(1)文件描述符相当于文件的索引。
在linux中有三个默认的的文件描述符:
0 | 标准输入 |
1 | 标准输出 |
2 | 标准错误 |
demo7
我们先从标准输入里面读取数据到readbuf里,然后再把readbuf里的数据标准输出。
#include<unistd.h>
#include<string.h>
#include<stdio.h>
int main()
{
int fd;
char readbuf[128];
int n_read = read(0,readbuf,5); // 0 Standard input
int n_write = write(1,readbuf,strlen(readbuf));// 1 Standard output
printf("\nDone\n");
return 0;
}
(2)文件描述符的作用域就是当前进程,出了这个进程 文件描述符就没有意义了。
open函数打开文件,打开成功返回一个文件描述符,打开失败,返回-1.
2.在linux 打开/创建/读取/写入/关闭 文件
(1).在linux中要操作一个文件,一般是先open打开一个文件,得到文件描述符,然后对文件进行读写操作(或其他操作),最后是close关闭文件。
(2)文件读写完成后,一定要关闭文件,否则会造成文件损坏。
(3)静态文件和动态文件
静态文件 | 动态文件 |
---|---|
存放在磁盘中的文件(如桌面文件等) | open静态文件后,会在Linux内核产生一个结构体(数据结构),来记录这个文件,内核在内存中申请一段内存,将静态文件的内容从块设备中读取到内核中特定地址管理存放。 |
(4)
(5)为什么不直接对块设备直接操作?
答:块设备本身读写不灵活,是按块读写的,而内存是按字节单位操作的,而且可以随机操作,很灵活。
八.文件编程实例 (实现linux cp命令的代码)
demo_8_1.c
cp src.c des.c
c语言参数:
#include<stdio.h>
int main(int argc,char **argv)
{
printf("total params:%d\n",argc);
printf("NO1 params:%s\n",argv[0]);
printf("NO2 params:%s\n",argv[1]);
printf("NO3 params:%s\n",argv[2]);
return 0;
}
运行结果:
demo8_2.c
思路:
- 打开src.c
- 读src到buf
- 打开/创建des.c
- 将buf写入到des.c
- close两个文件
#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("params error\n"); //params 参数
exit(-1);
}
fdSrc = open(argv[1],O_RDWR); //打开src文件
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); //读取src文件内容,存储到readbuf中
fdDes = open(argv[2],O_RDWR|O_CREAT|O_TRUNC,0600);//打开Des文件
int n_write = write(fdDes,readbuf,strlen(readbuf));//将readbuf里的内容写入到Des文件中
close(fdSrc);
close(fdDes);
return 0;
}
注:O_TRUNC属性去打开文件时,如果这个文件中本来是由内容的,而且为只读或只写成功打开,则将其长度截短为0.
九.修改程序文件
1.先创建一个 .txt 文件。
demo9.c
- 先找到文件内容“LENG=”位置。
- 从该位置往后移动,移动到想要修改的地方。
- 修改该位置的内容。
#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("params error\n"); //params 参数
exit(-1);
}
fdSrc = open(argv[1],O_RDWR); //打开src文件
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); //读取src文件内容,存储到readbuf中
//char *strstr(const char *haystack, const char *needle);
char *p = strstr(readbuf,"LENG=");
if(p == NULL)
{
printf("No found\n");
exit(-1);
}
p = p + strlen("LENG=");
*p = '5';
lseek(fdSrc,0,SEEK_SET);
int n_write = write(fdSrc,readbuf,strlen(readbuf));//将readbuf里的内容写入到Des文件中
close(fdSrc);
return 0;
}
运行结果:
十. 写一个整数 ,结构体,数组到文件
1.写一个整数
demo10_1.c
#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 fdSrc;
int data1=100;
int data2;
fdSrc = open("./file10",O_RDWR); //打开src文件
int n_write = write(fdSrc,&data1,sizeof(int));//将readbuf里的内容写入到Des文件中
lseek(fdSrc,0,SEEK_SET);
int n_read = read(fdSrc,&data2,sizeof(int));
printf("read:%d,context:%d\n",n_read,data2);
close(fdSrc);
return 0;
}
2.写一个结构体数组
demo10_2.c
#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 b;
};
int main()
{
int fdSrc;
struct Test data1[2]={{100,'a'},{101,'b'}};
struct Test data2[2];
fdSrc = open("./file10",O_RDWR); //打开src文件
int n_write = write(fdSrc,&data1,sizeof(struct Test)*2);//将readbuf里的内容写入到Des文件中
lseek(fdSrc,0,SEEK_SET);
int n_read = read(fdSrc,&data2,sizeof(struct Test)*2);
printf("read:%d,%c\n",data2[0].a,data2[0].b);
printf("read:%d,%c\n",data2[1].a,data2[1].b);
close(fdSrc);
return 0;
}
结果:
十一.标准c库对文件操作引入
fopen fread fwrite fseek fclose fgetc fputc feof
1.与之前的open等有什么区别?
参考:总结open与fopen的区别
2.相关API
(1)标准c库打开/创建/读写文件,光标移动
先看下下面这张图:
demo11_1.c
#include<stdio.h>
#include<string.h>
int main()
{
FILE *fp;
char *str = "FLG is very good!";
char readbuf[128]={0};
//FILE *fopen(const char *pathname, const char *mode);
fp = fopen("./fan.txt","w+");
//size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
// ptr buf
// size sizeof char
// 个数
// which file
fwrite(str, sizeof(char),strlen(str),fp);
//int fseek(FILE *stream, long offset, int whence);
fseek(fp,0,SEEK_SET);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream
fread(readbuf,sizeof(char),strlen(str),fp);
printf("read data:%s\n",readbuf);
fclose(fp);
}
demo11_2.c
c标准库写一个结构体到文件
#include<stdio.h>
#include<string.h>
struct test
{
int a;
char b;
};
int main()
{
FILE *fp;
struct test data1[2]={{100,'a'},{101,'b'}};
struct test data2[2];
//FILE *fopen(const char *pathname, const char *mode);
fp = fopen("./fan.txt","w+");
//size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
// ptr buf
// size sizeof char
// 个数
// which file
fwrite(&data1, sizeof(struct test),1,fp);
//int fseek(FILE *stream, long offset, int whence);
fseek(fp,0,SEEK_SET);
//size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream
fread(&data2,sizeof(struct test),1,fp);
printf("read data:%d,%c\n",data2[0].a,data2[0].b);
printf("read data:%d,%c\n",data2[1].a,data2[1].b);
fclose(fp);
}
(2)fgetc, fputc, feof 用法
(可通过man fputc 查看fputc的参数,用法)
_1.fputc
#include<stdio.h>
#include<string.h>
int main()
{
FILE *fp;
int i;
char *str = "FLG is good!";
fp = fopen("./text12.txt","w+");
int len = strlen(str);
//for(i=0;i<strlen(str);i++)
for(i=0;i<len;i++) // str每循环一次,指向后一个字节,strlen(str)的长度会减小,所以这块用len提前记录最开始str的长度。
{
fputc(*str,fp);
str++;
}
fclose(fp);
return 0;
}
**_2.feof **
用来判断是否到达文件尾巴
若 到达文件尾巴,则返回非零,没有到达文件尾巴,返回0,
fgetc 文件输入
_2. feof fgetc
#include<stdio.h>
#include<string.h>
int main()
{
FILE *fp;
int i;
char c;
fp = fopen("./text12.txt","r");
while(!feof(fp)){ // 没有到达文件尾巴,返回0, 再加上它的否定!,为非零,进入循环;
//等最后一次循环结束后判断时,此时已经到达文件尾巴,返回非零,再取反,为0, 所以退出while
c = fgetc(fp);
printf("%c",c);
}
printf("\n");
fclose(fp);
return 0;
}