LINUX系统编程之文件编程

文件系统编程

什么是文件 ---- 一种通用的接口

“文件”这个名词不陌生,什么是文件?

系统资源(内存、硬盘、一般设备、进程间通信的通道等)的一个抽象

对系统资源进行访问的一个通用接口。

采用这种“文件”的方式有什么好处?

对资源提供通用的操作接口,可以极大地简化系统编程接口的设计。

既然文件是一个通用的接口,由于系统资源多种多样,是不是意味着文件类型也多种多样?

常用文件类型

常见的文件类型(可以通过文件来访问的系统资源)有:

· 普通文件

​ 一般意义上的文件,作为数据存储在磁盘中,可以随机访问文件的内容。Linux系统中的文件是面向字节的,文件的内容以字节为单位进行存储和访问。

· 目录

​ 目录是一种特殊的文件,目录可以像普通文件一样打开、关闭以及进行相应的操作。

· 管道

​ 管道是Linux中的一种进程间通信的机制。

· 设备文件

​ 设备文件没有具体的内容,对设备文件的读写操作实际上与某个设备的输入输出操作关联在一起。

· 符号链接

​ 符号链接的内容是指向另一个文件的路径。当对符号链接进行操作时,系统会根据情况将这个操作转移到它所指向的文件上去,而不是对它本身进行操作。

· socket

​ socket也是一种进程间通信的方式,与管道不同的是,它们可以在不同的主机上进行通信,也就是网络通信。

如何表示文件?

所有执行I/O操作的系统调用使用文件描述符来表示打开的文件。

· 文件描述符是一个非负整数。

· 文件描述符可以表示各种类型的打开的文件。

· 对文件的操作只要使用文件描述符即可指定所操作的文件。

如何获得文件描述符?获得文件描述符以后如何进行文件操作?

· 打开文件,打开成功后,应用程序将获得文件描述符。

· 应用程序使用文件描述符对文件进行读写等操作。

· 全部操作完毕后,应用程序需要将文件关闭以释放用于管理打开文件的内存。

文件描述符和打开文件之间的关系

内核使用三种数据结构表示一个打开的文件

· 文件描述符表(每个进程都有)

​ (1) 文件描述符标志(file descriptor flags),如:close_on_exec。

​ (2) 指向一个文件表项(file table entry)的指针。

· 打开文件表(open file table)

​ (1) 文件状态标志(file status flags),如读、写、非阻塞等。

​ (2) 当前文件偏移量(file offset)。

​ (3) 文件访问模式(read-only, write-only, or read-write)。

​ (4) 指向i-node表项的指针。清楚上述问题,首先需要了解内核如何表示打开的文件

· 文件系统i-node表

​ (1) 文件类型(regular file, socket, or FIFO)和权限。

​ (2) 指向文件表的指针。

​ (3) 文件的属性(file size等)。

在这里插入图片描述

系统调用

LINUX系统是通过文件描述符来管理文件的(类似于通过地址管理内存)

1、每一个程序运行 默认打开三个文件

文件文件指针文件描述符(数字)
标准输入文件从键盘获取数据stdin0
标准输出文件在屏幕上显示正确的数据stdout1
标准错误文件在屏幕上显示错误的数据stderror2

成功打开文件会返回文件描述符,选取当前最小的文件描述符返回

失败打开文件会返回 -1

通过linux系统内核提供的全局变量 errno 可查看错误号
通过库提供的函数perror来查看错误信息

在这里插入图片描述

查看帮助手册

命令man 2 函数名

打开文件

系统函数:open
函数原型int open(const char *pathname, int flags); int open(const char *pathname, int flags, mode_t mode);

关闭文件

系统函数:close
函数原型int close(int fd);

读文件

系统函数:read
函数原型ssize_t read(int fd, void *buf, size_t count);

写文件

系统函数:write
函数原型ssize_t write(int fd, const void *buf, size_t count);

改变文件偏移量

lseek系统调用可以改变文件偏移量(File Offset)。文件偏移量是一个整数,表示距文件起始处的字节数。 ===> 改变文件指针

系统函数:lseek
函数原型off_t lseek(int fd, off_t offset, int whence);

复制文件描述符表中的文件指针

系统函数:dup 和 dup2
函数原型int dup(int oldfd); int dup2(int oldfd, int newfd);

标准库函数

IO缓冲

C标准库提供了操作文件的标准I/O函数库,与系统调用相比,主要差别是实现了一个跨平台的用户态缓冲的解决方案。

例如:

在这里插入图片描述

为什么要采用这种缓冲机制?

​ 为了提高系统进行I/O操作的效率!

​ 系统调用要请求内核的服务,会引发CPU模式的切换,期间会有大量的堆栈数据保存操作,开销比较大。如果频繁地进行系统调用,会降低应用程序的运行效率。有了缓冲机制以后,多个读写操作可以合并为一次系统调用,减少了系统调用的次数,将大大提高程序的运行效率。

​ 所谓的标准I/O函数实际上是对底层系统调用的封装,最终读写设备或文件的操作仍需调用系统I/O函数来完成。

标准I/O函数使用文件指针操作文件

​ 标准I/O函数并不直接操作文件描述符,而是使用文件指针。文件指针和文件描述符是一一对应的关系,这种对应关系由标准I/O库自己内部维护。文件指针指向的数据类型为FILE型,但应用程序无须关心它的具体内容。

​ 在标准I/O中,一个打开的文件称为流(stream),流可以用于读(输入流)、写(输出流)或读写(输入输出流)。每个进程在启动后就会打开三个流,分别对应:stdin(标准输入流)、stdout(标准输出流)以及stderr(标准错误输出流)。

文件操作

查看帮助手册

命令man 3 函数名

打开文件

标准库函数fopen
函数原型FILE *fopen(const char *path, const char *mode); FILE *fdopen(int fd, const char *mode); FILE *freopen(const char *path, const char *mode, FILE *stream);
“r"或"rb”:以只读方式打开。
“w"或"wb”:以只写方式打开,并把文件长度截短为零。
“a"或"ab”:以写方式打开,新内容追加在文件尾。
"r+"或"rb+“或"r+b”:以更新方式打开(读和写)。
"w+"或"wb+“或"w+b”:以更新方式打开,并把文件长度截短为零。
"a+"或"ab+“或"a+b”:以更新方式打开,新内容追加在文件尾。

注:字母b表示文件是一个二进制文件而不是文本文件。

关闭文件

标准库函数fclose
函数原型int fclose(FILE *fp);

读文件

标准库函数fread
函数原型size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

###· 写文件

标准库函数fwrite
函数原型size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

###· 清空缓冲区

标准库函数fflush
函数原型int fflush(FILE *stream);

###· 改变文件指针下次读写操作的位置

标准库函数fseek
函数原型int fseek(FILE *stream, long offset, int whence);

//读文件

fgetc()从文件流里取出下一个字节并把它作为一个字符返回。当它到达文件结尾或出现错误时,返回EOF。getc()和fgetc()一样,但它有可能被实现为一个宏。getchar()相当于getc(stdin)。

#include <stdio.h>

int fgetc(FILE *stream);

int getc(FILE *stream);

int getchar(void);

fgets : 一行一行的读

//写文件

fputc()把一个字符写到一个输出文件流中,它返回写入的值,如果失败,则返回EOF。类似fgetc()和getc(),putc()的作用也相当于fputc(),但它可能被实现为一个宏。putchar()相当于putc(c, stdout),它把单个字符写到标准输出。

#include <stdio.h>

int fputc(int c, FILE *stream);

int putc(int c, FILE *stream);

int putchar(int c);

注意:putchar和getchar都是把字符当作int类型而不是char类型来使用的,这就允许文件结尾EOF取值为-1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值