分享

UC头条:Linux基础IO[文件操作]

 cnzrp 2023-09-26 发布于山西

前面讲过C语言的文件操作,文件操作是基础IO的重要部分,下面我们就来学习一下Linux中的文件操作

1.文件认识

先来讲述对于文件的几个疑问

文件是怎么构成的,放在哪里?

文件=内容+属性

文件被分为两大类:磁盘文件、内存文件(被打开的文件)

文件没有被操作的时候,一般放在磁盘上

文件被操作的时候,文件属性会被加载到内存中,冯诺依曼体系规定

文件操作的本质是什么?

对文件的操作无非就两种:对内容进行操作或者对属性进行操作,这里讲述后者

文件操作本质就是将需要的文件属性加载到内存中,操作系统一定同时存在大量的被打开的文件,同时操作系统也要管理这些被打开的文件,通过先描述再组织的方式

先描述就是构建在内存中的文件结构体structfile,来存储文件属性进行管理,这个结构体可以从磁盘上拿到,再组织就是通过数据结构来组织,比如:链表来连接结构体节点

文件是谁打开的?

文件是被操作系统打开的,是由用户创建进程,进程让操作系统完成打开文件的任务

所有语言的文件操作,本质上都是调用系统级接口进行操作,要针对底层系统级文件操作进行学习

2.回顾C文件接口

先来回顾一下C语言的文件操作

2.1打开文件

使用fopen函数打开文件

FILE*fopen(constchar*filename,constchar*mode);

fopen函数

返回值:打开文件失败返回NULL

filename参数:要打开的文件名,直接使用文件名,此文件需要位于当前程序目录下,可以使用绝对路径来指定目录存放

mode参数:文件打开方式

w:只写,文件写入前会先清空文件原内容,如果文件不存在会自动创建它

a:追加,在文件末尾对文件追加写入内容,不会清空原内容

r:只读,打开指定文件进行读取操作,如果文件不存在则会打开失败

w+、a+、r+:可读可写、可读可追加、可读可写,其中只有r+不会自动创建文件

2.2关闭文件

文件打开使用完后需要关闭,使用fclose函数关闭文件

intfclose(FILE*stream);

对FILE*指针进行操作,只能关闭已打开的文件,文件不存在会报错

FILE*fd=fopen('text.txt','w');//打开文件//...文件使用...fclose(fd);//关闭文件

2.3文件写入

C语言中的文件写入方式

intfputc(intcharacter,FILE*stream);//逐字符写入intfputs(constchar*str,FILE*stream);//逐行写入size_tfwrite(constvoid*ptr,size_tsize,size_tcount,FILE*stream);//二进制格式化写入intfprintf(FILE*stream,constchar*format,...);//格式化写入intsnprintf(char*s,size_tn,constchar*format,...);

前几个都比较简单,来讲解一下snprintf

s参数:缓冲区

n参数:缓冲区大小

format参数:格式化输入

使用snprintf函数将数据写到缓冲区后,可以通过fputs函数将缓冲区中的数据写入文件中

#include#defineTEXT'text.txt'intmain{FILE*fd=fopen(TEXT,'w');if(fd==NULL){perror('fopenfail!');exit(-1);}constchar*message='helloworld';charbuffer[256];//缓冲区intn=5;while(n--){snprintf(buffer,sizeof(buffer),'%s%d\n',message,n);//向缓冲区写入内容fputs(buffer,fd);//将缓冲区中的内容写入文件}fclose(fd);return0;}

点击加载图片

2.4文件读取

C语言中的文件读取方式

intfgetc(FILE*stream);char*fgets(char*str,intnum,FILE*stream);size_tfread(void*ptr,size_tsize,size_tcount,FILE*stream);intfscanf(FILE*stream,constchar*format,...);intsscanf(constchar*s,constchar*format,...);

这里的sscanf用于按照一定规则格式化读取字符串

#includeintmain{chars[]='2023,7,20';intarr[3];char*buffer[4];sscanf(s,'%d,%d,%d',arr,arr+1,arr+2);printf('%d%d%d\n',arr[0],arr[1],arr[2]);return0;}

点击加载图片

3.系统文件操作接口

3.1打开文件open

系统级打开文件接口open

#include#include#includeintopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);

open函数讲解

返回值:成功返回新打开的文件描述符,失败返回-1

pathname参数:待操作文件名

flags参数:打开文件时,可以传入多个参数选项构成

mode参数:权限设置,文件默认权限为0666

讲解一下flags参数

flags是一个int类型的变量,它有32个比特位,这里选项有很多,如O_APPEND、O_CREAT、O_TRUNC等

32个比特位每一个都可以表示一个标志位,这样就有32个标志位,也就是对应的可以有32个选项。这种数据结构就是是位图,使用位图进行多参数传递

知道了特性,下面用一个小demo来展示一下位图

#include#defineONE0x1#defineTWO0x2#defineTHREE0x4//模拟实现选项传递voidout(intflags){if(flags&ONE)printf('1111\n');if(flags&TWO)printf('2222\n');if(flags&THREE)printf('3333\n');}intmain{out(ONE);printf('-----------\n');out(TWO);printf('-----------\n');out(ONE|TWO);printf('-----------\n');out(ONE|TWO|THREE);printf('-----------\n');return0;}

点击加载图片

每个比特位来设置一个选项,可以直接通过传入参数的形式执行不同的功能

列举几个open系统调用中的flags选项

O_APPEND//文件用追加的方式被打开O_CREAT//如果文件不存在就会自动创建O_RDONLY//只读模式O_WRONLY//只写模式O_TRUNC//清理文件

试用一下

#include#include#include#include#include#include#include#defineTEXT'text.txt'intmain{//两种参数组合体现fopen中的a选项intfd=open(TEXT,O_CREAT|O_WRONLY,0666);//权限最好加上if(fd==-1){perror('openfail1');return;}else{printf('fd:%d,errno:%d,errstring:%s\n',fd,errno,strerror(errno));}close(fd);return0;}

点击加载图片

这里的mode是权限,有以下几种情况

S_IRWXU00700user(fileowner)hasread,writeandexecutepermission

S_IRUSR00400userhasreadpermission

S_IWUSR00200userhaswritepermission

S_IXUSR00100userhasexecutepermission

S_IRWXG00070grouphasread,writeandexecutepermission

S_IRGRP00040grouphasreadpermission

S_IWGRP00020grouphaswritepermission

S_IXGRP00010grouphasexecutepermission

S_IRWXO00007othershaveread,writeandexecutepermission

S_IROTH00004othershavereadpermission

S_IWOTH00002othershavewritepermission

S_IXOTH00001othershaveexecutepermission

注意:

权限可以直接以数字的形式给出

若文件不存在,mode参数最好设置,不然的话创建出的文件权限是随机值

umask默认为0002,可以自定义

3.2关闭文件close

系统级关闭文件接口close,它是根据文件描述符来关闭文件的

#includeintclose(intfildes);

Linux下的三个标准流为:stdin、stdout、stderr,分别对应的文件描述符为:0、1、2,可以通过close(1)来关闭标准流

3.3文件写入write

系统级文件写入接口write

#includessize_twrite(intfildes,constvoid*buf,size_tnbyte);

使用方法与fwrite基本相同,返回值有所差异:成功返回写入的字节总数,失败返回-1并且errno被设置

#include#include#include#include#include#include#include#defineTEXT'text.txt'intmain{//三种参数组合体现fopen中的w选择intfd=open(TEXT,O_WRONLY|O_CREAT|O_TRUNC,0666);if(fd==-1){perror('openfail1');return;}else{printf('fd:%d,errno:%d,errstring:%s\n',fd,errno,strerror(errno));}constchar*message='helloworld\n';intcount=5;while(count--){write(fd,message,strlen(message));//这里不能将'\0'写入文件中}close(fd);return0;}

点击加载图片

注意:使用write写入字符串时,不要加上'\0'当作结尾,因为对于系统来说,'\0'也是个普通的字符,'\0'作为字符串结尾只是C语言的规定

3.4文件读取read

系统级文件读取接口read

#includessize_tread(intfildes,void*buf,size_tnbyte);

read函数在读取文件时,也是借助缓冲区进行读取,不过只支持按指定字符数读取,无法按行读取,返回值和write相同

//读取text.txt中内容#include#include#include#include#include#include#include#defineTEXT'text.txt'intmain{intfd=open(TEXT,O_RDONLY,0664);if(fd==-1){perror('openfail1');return;}charbuffer[256];//缓冲区size_tret=read(fd,buffer,sizeof(buffer)-1);if(ret>0){buffer[ret]='\0';printf('%s\n',buffer);}close(fd);return0;}

点击加载图片

//读取myfile.c中的66个字符#include#include#include#include#include#include#include#defineTEXT'myfile.c'intmain{intfd=open(TEXT,O_RDONLY,0664);if(fd==-1){perror('openfail1');return;}intn=66;//要读取的字符数charbuffer[256];intpos=0;while(n--){read(fd,(char*)buffer+pos,1);pos++;}printf('%s\n',buffer);close(fd);return0;}

点击加载图片

4.系统调用和库函数

我们上面回顾了C语言的文件操作库函数,讲解了文件操作系统级的接口,在Linux下,无论是什么语言,在进行文件操作时所使用的函数,本质上都是对系统调用接口的封装,在文件操作中,是无法直接与硬件(磁盘)交互的,必须经过系统调用接口到操作系统再到驱动程序这一途径

点击加载图片

Linux基础IO[文件操作],到这里就介绍结束了,本篇文章对你由帮助的话,期待大佬们的三连,你们的支持是我最大的动力!

文章有写的不足或是错误的地方,欢迎评论或私信指出,我会在第一时间改正

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多