目录
前言
在linux下操作文件可以用C语言那一套,使用fopen,fwrite,fread,fseek和fclose等函数即可完成基本文件操作,也可以用linux的系统调用接口:open、write、read、lseek和close
C文件操作
c文件操作之前说过了,这次就直接把代码放到linux下运行:
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
int main(){
char* s="Linux is so easy!";
int size=strlen(s);
char buf[20]={0};
FILE *fd=fopen("bite","wb+");
if(fd==NULL){
printf("fopen failed!");
exit(-1);
}
fwrite(s,sizeof(char),size,fd);
//fclose(fd);
//FILE* fp=fopen("bite","wb+"); //再次打开 用fp(不同名称)
fseek(fd,0,SEEK_SET);
fread(buf,sizeof(char),size,fd);
printf("%s\n",buf);
fclose(fd);
printf("over\n");
return 0;
}
Linux系统调用文件操作
系统调用接口相比于c文件操作的函数调用,每个函数名都少了开头的 f ,但实际上功能都基本相同,以下用代码示范(有些许问题):
问题代码
int main(){
char *s="I love Linux sososososososo much!";
int size=strlen(s);
char buf[50]={0};
int fd=open("./bite3",O_RDWR,0644);
if(fd>0){
printf("success!\n");
}else{// 打开失败则进入下一步,需要重新打开
printf("failed!\n");
perror("open error:");
printf("\n");
printf("Accepting.Rerouted!\n"); //提示将再次打开
printf("Alternatives_Opertion_Phoenix......Initiated!\n");
fd=open("./bite2",O_RDWR | O_CREAT | O_TRUNC);
if(fd>0){ //再次打开成功则提示
printf("Success!\n");
}else{ //再次打开失败则提示
printf("open failed!\n");
perror("open error:");
}
}
write(fd,s,size);
lseek(fd,0,SEEK_SET);
read(fd,buf,size);
printf("ALready to read file:\n");
printf("Contxt:%s",buf);
printf("\n over \n");
close(fd);
return 0;
}
实际上上面代码在运行时一直出错,我查找了半天发现都是无法创建文件,系统报错说我没有相关权限,很奇怪,因为我换成fopen就可以运行,我试了很多办法也没用
但意外的我重新再写一个程序,让那个新程序只执行open创建文件,然后创建好文件后再用上面的代码运行就可以了。(也就是说问题出在不存在文件时没有权限创建,但其实这不应该,有可能是我的电脑或是编译器有问题或者是用户权限不足)
具体原因我也无法查询,总之错在第二次创建时没有权限,那我就修改一下代码,将其变成第一次创建就成功其实就可以运行了(之前的代码是我故意设计成第一次创建失败,需要创建第二次的)
修改后的正确代码
与上面唯一的不同就在第14行,保证了没有文件时创建文件
9 int main(){
W> 10 char *s="I love Linux sososososososo much!";
11 int size=strlen(s);
12 char buf[50]={0};
13
14 int fd=open("./bite3",O_RDWR | O_CREAT | O_TRUNC,0644); //直接创建成功
15 if(fd>0){
16 printf("success!\n"); //直接创建成功
17 }else{ //因为一次就创建成功所以不会运行else里的代码
18 printf("failed!\n");
19 perror("open error:");
20 printf("\n");
21
22 printf("Accepting.Rerouted!\n");
23 printf("Alternatives_Opertion_Phoenix......Initiated!\n");
24
25 fd=open("./bite2",O_RDWR | O_CREAT | O_TRUNC,0664); 26 //因为一次就创建成功,也不需要创建第二次
27 if(fd>0){
28 printf("Success!\n");
29 }else{
30 perror("open error:");
31 }
32 }
33
34 write(fd,s,size);
35 lseek(fd,0,SEEK_SET);
36
37 read(fd,buf,size);
38 printf("ALready to read file:\n");
39 printf("Contxt:%s",buf);
40 printf("\n over \n");
41 close(fd);
42 return 0;
43 }
系统调用接口
① open: int open(char* pathname,int flag,int mode)
open是不定参接口(参数个数不定),
里面的flag是打开方式有三个必选项:O_RDONLY(只读)、O_WRONLY(只写)、O_RDWR(可读可写),这三个里面必选其中一个,注意如果要可读可以,不能写成 O_RDONLY | O_WRONLY 因为这三个符号在内存里其实是00000000(只读)、00000001(只写)、00000010(可读可写),所以O_RDONLY | O_WRONLY其实是00000000 | 00000001 =00000001,还是只写。
flag可选项:O_CREAT(文件不存在时则创建)
O_TRUNC(截断文件,丢弃原数据)
O_APPEND(追加写入)
例如 w+ 可以表示为: O_RDWR | O_CREAT | O_TRUNC
open里的mode:当O_CREAT被使用时,就得设置mode,用于设置文件访问权限,例如0644(前面的0不能省略,会出现混乱)
②write: ssize_t write(int fd,char* buf,size_t len)
fd:open打开文件时返回的操作句柄(也叫文件描述符)
buf: 要写入的文件地址
len:要写入的数据长度
write返回值:成功时返回实际写入长度,失败返回-1
③read:ssize_t read(int fd,char* buf, size_t len)
fd:和write的一样
buf:一块空间首地址,用于存放读入的数据
len:要读的数据长度
④lseek:off_t lseek(int fd,off_t offset,int whence)
fd:和前两个一样
offset:偏移量
whence:偏移的起始地址(只能是SEEK_SET、SEEK_CUR、SEEK_END三个中的一个)
lseek的返回值可用于确定文件大小,lseek执行成功时,它会返回最终以文件起始位置为起点的偏移位置。如果出错,则返回-1,同时errno被设置为对应的错误值
⑤close:int close(int fd)
fd:和前面的一样
文件描述符为什么是int类型
fd(文件描述符),在进程中每打开一个文件,都会创建有相应的文件描述信息struct file,这个描述信息被添加在pcb的struct files_struct中,以数组的形式进行管理,随即向用户返回数组的下标作为文件描述符,用于操作文件。
本来描述文件需要很多信息,这些信息都保存在一个结构体数组中,为了更方便描述一个文件,就直接采用这个信息结构体的数组下标来作为文件描述符。