## Linux I/O——文件操作1 ##

1 篇文章 0 订阅
1 篇文章 0 订阅
以前从来不写技术博客,因为我觉得花一两个小时来写篇博客还不如多写几行代码,但我发现我错了,每次需要搭一些框架或者想回忆起某个知识点时,却发现大脑对那些知识点只有一个轮廓,却不清晰,就像近视的人摘掉眼镜后看东西一样不自信。所以,从今天开始,我会将每天所学的知识记录下来,以便以后复习之用。

1、说到Linux文件操作,得先说一下Linux的文件系统。

Linux的文件系统。

文件包含在目录之中,目录由包含子目录,这些构成了Linux文件系统的树状层次结构。可用tree命令查看:
tree -L 1 /


  1. 普通文件:代码文件、可执行文件等,分为纯文本和二进制文本
  2. 目录文件:存放其他文件的节点号和名字的文件。
  3. 链接文件:指向一个文件或目录的文件
  4. 特殊文件:与外部设备相关,分为块设备和字符设备。

一个文件有目录项、inode和数据块组成,目录项包含文件名和inode节点号,inode包含文件的元信息,如何文件的大小,拥有者,rwx权限,链接数,时间戳,文件数据block等信息,数据块是文件内容存放地。

系统调用和设备驱动程序

只需要调用少量函数即可度文件和设备进行访问和控制,这些函数称为系统调用,由操作系统直接提供,是面向操作系统的接口。
操作系统的核心部分——内核,是一组设备驱动程序,对系统硬件进行控制的底层接口,其封装了所有与硬件相关的特性。ioctl函数提供硬件特有的功能


访问设备驱动程序的底层函数如下:
  1. open:打开文件或设备
  2. read:从打开的文件或设备读取数据
  3. write:向文件或设备写数据
  4. close:关闭文件
  5. ioctl:把控制信息传递给设备驱动程序(提供与设备相关的必要控制,用法随设备的不同而不同,所以不具备可移植性)

值得注意的是,只对输入输出操作直接使用系统调用的效率非常低,原因如下:
  • 在执行系统调用时,Linux必须从运行用户的代码切换到执行内核代码,然后返回用户代码,这是一个开销。而减少这种开销的好方法是,在程序中尽可能减少系统调用的次数,并且每次系统调用都尽可能的完成多的工作。
  • 硬件会限制对底层系统调用一次所能读写的数据块的大小。
为了给设备和磁盘文件提供更高层的借口,Linux提供了一系列的标准库函数,简而言之


2、文件操作
每个运行中的程序被称为进程,它有一些与之关联的文件描述符——打开文件的索引,当一个程序运行时,一般有3个已经打开的文件描述符:

  • 0:标准输入
  • 1:标注输出
  • 2:标准错误
系统调用函数函数原型头文件
writesize_t write(int fildes, const void *buf, size_t nbytes)unistd.h
readsize_t read(int fildes, void *buf, size_t nbytes)unistd.h
openint open(const char *path, int oflags, mode_t mode)fcntl.h
closeint close(int fildes)unistd.h
ioctlint ioctl(int fildes, int cmd, …)unistd.h
lseekoff_t lseek(int fildes, off_t offset, int whence)unistd.h
fstatint fstat(int fildes, struct stat *buf)unistd.h
statint stat(const char *path, struct stat *buf)unistd.h
lstatint lstat(const char *path, struct stat *buf)unistd.h
dupint dup(int fildes)unistd.h
dup2int dup2(int fildes, int fildes2)unistd.h

1、write函数:fildes表示要操作的文件描述符, buf表示缓冲区, nbytes表示缓冲区的前nbytes个字节。返回值表示写入字节数,但若返回-1,则表示函数调用错误,错误代码保存在全局变量errno里。
2、read函数:fildes表示要操作的文件描述符, buf表示数据区,nbytes表示读入nbytes个字节的数据。返回值表示读入的字节数,如果返回-1,则表示函数调用错误。
3、open函数:path表示要操作的文件路径,如果函数调用成功,则返回一个文件描述符,若失败则返回-1,并设置全局变量errno指明失败原因。这个文件描述符是唯一的,不与其他进程共享的。oflags指定打开文件的操作,具体模式在下表表示, mode表示访问权限。
4、close函数:fildes表示文件描述符。
5、ioctl函数:fildes表示文件描述符, cmd表示操作。
6、lseek函数:fildes表示文件描述,offset指定位置。whence表示偏移的方法,有三个取值,SEEK_SET表示offset是一个绝对位置,SEEK_CUR表示offset是相对于当前位置的一个相对位置,SEEK_END表示offset是相对于文件尾的一个相对位置。lseek函数调用成功会返回一个文件头到当前位置的一个偏移值,若调用失败,会返回-1。
7、fstat函数返回与打开的文件描述符相关的文件状态信息,该信息存储于一个buf之中。
8、stat函数和lstat函数都是通过文件名查询状态信息,但如果文件是一个符号链接时,stat返回的是链接所指向的文件信息,而lstat返回的是符号链接本身的信息。stat结构位于sys/stat.h头文件中。
9、dup和dup2函数复制文件描述符,dup函数返回一个新的文件描述符,dup2通过明确指定目标描述符来把一个文件描述符复制为另外一个。

oflags参数说明

模式说明
O_RDONLY以只读方式打开
O_WRONLY以只写方式打开
O_RDWR以读写方式打开
O_APPEND以追加方式打开
O_TRUNC文件长度置为0,丢弃已有内容
O_CREAT按照参数mode创建文件
O_EXCL与O_CREAT一起使用,确保创建出文件

mode参数说明

权限说明
S_IRUSR读权限,文件属主
S_IWUSR写权限,文件属主
S_IXUSR执行权限,文件属主
S_IRGRP读权限,文件所属组
S_IWGRP写权限,文件所属组
S_IXGRP执行权限,文件所属组
S_IROTH读权限,其他用户
S_IWOTH写权限,其他用户
S_IXOTH执行权限,其他用户

值得注意的是,open的标志实际上是发出设置文件访问权限的请求,所请求的权限是否会被设置是取决于用户掩码umask的值。umask说明如下表。

数字取值含义
1(user)0允许属主任何权限
4禁止属主读权限
2禁止属主写权限
1禁止属主执行权限
2(group)0允许组的任何权限
4禁止组的读权限
2禁止组的写权限
1禁止组的执行权限
3(other)0允许其他用户任何权限
4禁止其他用户的读权限
2禁止其他用户的写权限
1禁止其他用户的执行权限

open调用的mode值会与用户掩码的反值做AND操作,例如,如果要禁止组的写和执行权限,同时禁止其他用户的写权限,则umask值应该是1->0, 2->2|1, 3->2,同个数字下的取值OR一起,最终umask值为032。此时如果mode设置为S_IWOTH,创建的文件其他用户也不会有写权限。

3、标准I/O库
标准I/O库及其头文件stdio.h为底层I/O系统调用提供一个通用的接口。同系统调用一样,使用I/O库时,你需要先打开一个文件,其返回值将作为其他函数的参数。与底层文件描述符相应的是流,它被实现为指向结构FILE的指针,程序启动时也有三个流是自动打开的。

  • 1、stdin:标准输入
  • 2、stdout:标准输出
  • 3、stderr:标准错误输出
库函数函数原型头文件
fopenFILE *fopen(const char *filename, const char *mode)stdio.h
fcloseint fclose(FILE *stream)stdio.h
freadsize_t fread(void *ptr, size_t size, size_t nitems, FILE *stream)stdio.h
fwritesize_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)stdio.h
fflushint fflush(FILE *streamstdio.h
fseekint fseek(FILE *stream, long int offset, int whence)stdio.h
fgetcint fgetc(FILE *stream)stdio.h
getcint getc(FILE *stream)stdio.h
getcharint getchar()stdio.h
fputcint fputc(int c, FILE *stream)stdio.h
putcint putc(int c, FILE *stream)stdio.h
putcharint putchar(int c)stdio.h
fgetschar *fgets(char *s, int n, FILE *stream)stdio.h
getschar *gets(char *s)stdio.h
printfint printf(const char *format, …)stdio.h
sprintfint sprintf(char *s, const char *format, …)stdio.h
fprintfint fprintf(FILE *stream, const char *format)stdio.h
scanfint scanf(const char *format, …)stdio.h
fscanfint fscanf(FILE *stream,const char *format, …)stdio.h
sscanfint sscanf(const char *s, const char *format, …)stdio.h

1、fopen函数类似于底层的open系统调用,主要用于文件和终端的输入输出,想对设备机型明确控制的话最好使用底层系统调用。filename参数是文件名,mode指定文件的打开方式,函数调用成功会返回FILE *指针,失败会返回NULL。可用的文件刘和文件描述符一样是有限制的,大小为在stdio.h头文件中定义的FOPEN_MAX的值。
2、fclose函数用于关闭指定的文件流,也能确保数据全部写出。
3、fread函数用于从一个文件里读取数据,数据从文件流stream读到ptr指向的数据缓冲区,size指定每个数据记录的长度,nitems给出要传输的记录个数。调用成功是返回读取到的数据缓冲区的记录个数。
4、fwrite函数与fread函数相似,ptr指向要写入文件流stream的数据缓冲区。
5、fflush函数用于将文件流中还未写出的数据立即写出,fclose函数隐含执行fflush。
6、fseek函数与lseek类似,参数offset和whence和lseek的offset和whence意义完全相似。
7、fgetc和getc函数从文件流读取下一个字符并返回,当到达文件尾或者出现错误时,会返回EOF。getchar函数相当于getc(stdin),表示从标准输入里读取下一个字符。
8、fputc和putc函数把一个字符写到输出文件流中,如果失败,则会返回EOF。putchar函数相当于putc(c, stdout),表示将一个字符写入标准输出流中。
9、fgets函数表示把从文件流中读到的字符写到s指向的字符串里,直到遇到换行符,或已经传输了n-1个字符,或已经到达文件尾。当函数调用成功时会返回一个指向字符串s的指针,如果已经到达文件尾,fgets会设置文件流的EOF标识并返回一个空指针,如果发生错误,则返回一个空指针并设置errno以指出错误类型。gets函数类似fgets,它从标准输入中读取数据并丢弃换行符。
10、printf函数把自己的输出输出到标准输出流,fprintf函数将自己的输出输出到文件流,sprintf函数将自己的输出输出到字符串。
11、scanf函数,fscanf函数和sscanf函数类似于prinf系列的函数,是将读取到的数值存放到变量之中。

mode参数说明

模式说明
“r”或”rb”以只读方式打开文件
“w”或”wb”以只写方式打开文件,并把文件长度截短为0
“a”或”ab”以只写方式打开文件,新内容追加到文件尾
“r+”或”r+b”或”rb+”以更新方式打开,(读或写)
“w+”或”w+b”或”wb+”以更新方式打开, 并把文件长度截短为0
“a+”或”a+b”或”ab+”以更新方式打开,新内容追加到文件尾
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值