1.文件IO

<br />#include <stdio.h><br />#include <stdlib.h><br />#include <string.h><br />#include <sys/types.h><br />#include <sys/stat.h><br />#include <unistd.h><br />#include <errno.h><br />#include <sys/wait.h><br />

```
vi /usr/include/unistd.h

/ Standard file descriptors. /
#define STDIN_FILENO 0 / Standard input. /
#define STDOUT_FILENO 1 / Standard output. /
#define STDERR_FILENO 2 / Standard error output. /
```

图片.png

open

描述: 打开或者新建一个文件
原型:
#include
#include
#include
int open(const char pathname, int flags);
int open(const char
pathname, int flags, mode_t mode);

返回值:
成功,返回最小且未被占用的文件描述符
失败,返回-1,设置errno值

参数:
pathname既可以绝对路径也可以是相对路径.
flags
O_RDONLY
O_WRONLY
O_RDWR
O_APPEND
O_CREAT 若文件不存在则创建
需要结合mode. 文件最终权限 mode & ~umask

man 2 open

其中关于flags之O_NONBLOCK的说明图片.png

close

描述: 关闭文件
原型:
#include
int close(int fd);

返回值:
成功返回0
失败返回-1,并设置errno值

参数:
文件描述符

man 2 close

进程终止时,内核对进程尚未关闭的文件描述符调用close关闭它.

read

描述: 从打开的设备或文件中读取数据
原型:
#include
ssize_t read(int fd, void *buf, size_t count);

返回值:
>0,读取到的字节数
=0,读取到文件末尾(针对普通文件)
=0,远程关闭(针对网络编程)
-1,出错,并设置errno

参数:
fd:文件描述符
bu:读取的数据保存在缓冲区buf中
count:buf缓冲区可存放的最大字节数

man 2 read man 3 fread

对于Java程序而言 =-1,读取到文件末尾(针对普通文件) 源码位置:jdk-jdk8-b116\jdk\src\share\native\java\io\io_util.c

write

描述: 向打开的设备或文件中写入数据
原型:
#include
ssize_t write(int fd, const void *buf, size_t count);

返回值:
成功,返回写入的字节数. 且仅表示数据写入到内核缓冲区.
失败,返回-1,并设置errno(针对普通文件)
失败,返回-1,并设置errno=EPIPE(针对网络编程)

参数:
fd:文件描述符
buf:待写入的数据
count:buf中实际数据的大小

man 2 write

lseek

描述: 移动文件指针
原型:
#include
#include
off_t lseek(int fd, off_t offset, int whence);

返回值:
成功,则返回新的偏移量

参数:
fd:文件描述符
offset:含义取决于参数whence
若whence是SEEK_SET,文件偏移量将设置到offset字节位置.
若whence是SEEK_CUR,文件偏移量将设置到(current’location + offset)字节位置
若whence是SEEK_END,文件偏移量将设置到(file’size + offset)字节位置.

offset 可以正负

lseek常用操作
1.文件指针移动到头部
lseek(fd, 0, SEEK_SET)
2.获取文件指针当前位置
int len = lseek(fd, 0, SEEK_CUR)
3.获取文件长度
int len = lseek(fd, 0, SEEK_END)
4.实现文件随机读写
off_t currpos = lseek(fd, 1000, SEEK_END); // 从文件尾部向后拓展1000个字节
write(fd, “v”, 1); // 额外执行一次写操作(数据任意), 否则文件无法完成拓展

产生空洞文件 [ 代码 ]
1.使用od命令可以查看空洞文件中的空洞

od -c tmp.txt

2.一个文件的大小不等于文件在磁盘所占用的空间
2.1若无空洞或空洞比较少,则文件大小<=所占磁盘空间 [ 图 ]
2.2若空洞比较大,则文件大小>所占磁盘空间
2.3空洞是否占用磁盘空间是由文件系统决定
3.查看文件所占磁盘空间

du -h tmp.txt

perror

描述:
原型:
#include
#include
#include
void perror(const char *s);

常见操作
1.perror(“Fail”);
2.fprintf(stderr, “Fail: %s\n”, strerror(errno));

查阅常见错误码 man 3 errno

2.标准IO

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

描述: 将文件指针转换为文件描述符
原型:
#include
int fileno(FILE *stream);

描述: 将文件描述符转换为文件指针
原型:
#include
FILE fdopen(int fd, const char mode);

3.文件与目录

3.1文件操作相关

stat/lstat

描述: 获取文件属性
原型:
#include
#include
#include
int stat(const char pathname, struct stat statbuf);
int lstat(const char pathname, struct stat statbuf);

返回值:
成功返回0
失败返回-1

```
struct stat {
dev_t st_dev; / ID of device containing file /
ino_t st_ino; / Inode number /
mode_t st_mode; / File type and mode / 文件类型和权限
nlink_t st_nlink; / Number of hard links /
uid_t st_uid; / User ID of owner /
gid_t st_gid; / Group ID of owner /
dev_t st_rdev; / Device ID (if special file) /
off_t st_size; / Total size, in bytes /
blksize_t st_blksize; / Block size for filesystem I/O /
blkcnt_t st_blocks; / Number of 512B blocks allocated /

/ Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES.
/

  1. struct timespec st_atim; /* Time of last access */<br /> struct timespec st_mtim; /* Time of last modification */<br /> struct timespec st_ctim; /* Time of last status change */
  2. #define st_atime st_atim.tv_sec /* Backward compatibility */<br /> #define st_mtime st_mtim.tv_sec<br /> #define st_ctime st_ctim.tv_sec<br />};<br />```

man 2 stat man 7 inode

使用stat判断文件类型 [ 代码 ]
使用stat判断文件权限 [ 代码 ]

3.2目录操作相关

opendir

描述: 打开一个目录
原型:
#include
#include
DIR opendir(const char name);

返回值:
指向目录的指针
参数:
绝对或相对路径

man 3 opendir

readdir

描述: 读取目录内容-目录项
原型:
#include
struct dirent readdir(DIR dirp);

返回值:
读取的目录项指针
参数:
指向目录的指针(即opendir函数的返回值)

目录中每个文件称为目录项

<br />struct dirent {<br /> ino_t d_ino; /* Inode number */<br /> off_t d_off; /* Not an offset; see below */<br /> unsigned short d_reclen; /* Length of this record */<br /> unsigned char d_type; /* Type of file; not supported<br /> by all filesystem types */ 文件类型<br /> char d_name[256]; /* Null-terminated filename */ 文件名<br />};<br />

文件类型如下
图片.png
块设备:应用程序可以随机访问设备数据.数据的读写必须以块的(通常512B)倍数进行操作,不支持基于字符的操作.
字符设备:提供连续的数据流,应用程序可以顺序读取,通常不支持随机存取.数据的读写按字节/字符进行操作.

closedir

描述: 关闭目录
原型:
#include
#include
int closedir(DIR *dirp);

返回值:
成功返回0
失败返回-1

读取目录内容一般步骤

1.DIR pDir = opendir(const char name);
2.while ( (p = readdir(pDir)) != NULL ) {}
3.closedir(pDir);

特别注意: 递归遍历指定目录下的所有文件的时候, 要过滤掉 ... 文件, 否则进入无限循环.

遍历目录 [ 代码 ]

3.3 dup

描述: 复制文件描述符,让复制出的新文件描述符指向与oldfd同一个文件.
原型:
#include
int dup(int oldfd);

返回值:
成功,返回最小且未被占用的文件描述符
失败,返回-1,设置errno值

参数:
oldfd表示要复制的文件描述符

newfd和oldfd指向同一个文件

man 2 dup

3.4 dup2

描述: 复制文件描述符,让newfd指向与oldfd同一个文件.
原型:
#include
int dup2(int oldfd, int newfd);

返回值:
成功返回0. 表示两个文件描述符指向同一个文件
失败返回-1,设置errno值

参数:
oldfd表示原文件描述符
newfd表示新文件描述符

如果newfd已经指向一个文件,则首先关闭已指向的文件,再指向oldfd表示的文件.

man 2 dup2

标准输出重定向 [ 代码 ]

3.5 fcntl

描述: 改变已打开文件的属性
原型:
#include
#include
int fcntl(int fd, int cmd, … / arg / );

若cmd是F_DUPFD, 复制文件描述符, 与dup相同 若cmd是F_GETFL, 获取文件描述符的flags属性值 若cmd是F_SETFL, 设置文件描述符的flags属性

返回值: 取决于cmd
成功
若cmd是F_DUPFD, 返回一个新的文件描述符
若cmd是F_GETFL, 返回文件描述符的flags属性值
若cmd是F_SETFL, 返回0
失败返回-1,设置errno值

man 2 fcntl

fcntl常用操作
1.复制一个新的文件描述符
int newfd = fcntl(fd, F_DUPFD, 0);
2.获取文件的属性标志
int flag = fcntl(fd, F_GETFL, 0);
3.设置文件属性标志
flag = flag | O_APPEND;
fcntl(fd, F_SETFL, flag);
4.常用属性标志
O_APPEND
O_NONBLOCK - 设置打开的文件描述符为非阻塞

4.其他

4.1宏的使用

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

vi /usr/include/stdlib.h
#define EXIT_FAILURE 1 / Failing exit status. /
#define EXIT_SUCCESS 0 / Successful exit status. /
```

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

4.2进程和系统打开文件最大数

进程打开文件最大数

ulimit -a ulimit -n

图片.png
系统打开文件最大数

cat /proc/sys/fs/file-max

图片.png