太一的博客

一个程序学徒

文件与IO

什么是I/O

  • 输入/输出是主存和外部设备之间拷贝数据的过程
    • 设备 -> 内存(输入操作)
    • 内存 -> 设备 (输出操作)
  • 高级I/O
    • ANSI C 提供的标准 I/O 库称为高级 I/O,通常也称为带缓冲的 I/O
  • 低级I/O
    • 通常也称为不带缓冲的 I/O

文件描述符

  • 对于 Linux 而言,所有对设备或文件的操作都是通过文件描述符进行的。
  • 当打开或者创建一个文件的时候,内核向进程返回一个文件描述符(非负整数)。后续对文件的操作只需通过该文件描述符,内核记录有关这个文件的信息。
  • 一个进程启动时,默认打开了 3 个文件,标准输入、标准输出、标准错误,对应文件描述符是 0( STDIN_FILENO )、1( STDOUT_FILENO)、2( STDERR_FILENO ),这些常量定义在 unistd.h 头文件中。

文件描述符与文件指针转换

  • fileno:将文件指针转换为文件描述符
  • fdopen:将文件描述符转换为文件指针

文件系统调用

open 系统调用

open系统调用1

int open(const char *path, int flags);

参数

  • path:文件的名称,可以包含(绝对和相对)路径
  • flags: 文件打开模式

返回值:

​ 打开成功,返回文件描述符

​ 打开失败,返回 -1

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

// #define ERR_EXIT(m) (perror(m), exit(EXIT_FAILURE))

#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)

int main(void)
{
int fd;
fd = open("test.txt", O_RDONLY);
if (fd == -1)
{
ERR_EXIT("open error");
}
printf("open success");
return 0;
}

open系统调用2

int open(const char *path, int flags, mode_t mode);

参数

  • path:文件的名称,可以包含(绝对和相对)路径
  • flags: 文件打开模式
  • mode: 用来规定对该文件的所有者,文件的用户组及系统中其他用户的访问权限

返回值:

​ 打开成功,返回文件描述符

​ 打开失败,返回 -1

close 系统调用

为了重新利用文件描述符,用 close() 系统调用释放打开的文件描述符

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

函数参数:

fd : 要关闭的文件的文件描述符

返回值

​ 如果出现错误,返回 -1

​ 调用成功返回 0

可打开的文件描述符个数

进程可打开的文件描述符个数 ulimit -n

系统可打开的文件描述符个数 cat /proc/sys/fs/file-max

read 系统调用

一旦有了与一个打开文件描述相连的文件描述符,只要该文件是用 O_RDONLY或O_RDWR标志打开的,就可以用 read() 系统调用从该文件中读取字节

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

函数参数:

​ **fd : **想要读的文件的文件描述符

​ **buf : ** 指向内存块的指针,从文件读取来的字节放在这个内存块中

​ **count : ** 从该文件复制到 buf 中的字节个数

返回值

​ 如果出现错误,返回 -1

​ 读文件结束,返回 0

​ 否则返回从该文件复制到规定的缓冲区中的字节数

write 系统调用

write() 系统调用将数据写到一个文件中

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

函数参数:

​ **fd : ** 要写入的文件的文件描述符

​ **buf : ** 指向内存块的指针,从这个内存块中读取数据写入到文件中

​ **count : ** 要写入文件的字节个数

返回值:

​ 如果出现错误,返回 -1

​ 如果写入成功,则返回写入到文件中的字节个数