文件 I/O

一、基础 API

1. open / close

#include <fcntl.h>
#include <unistd.h>

int fd = open("/dev/i2c-1", O_RDWR);
if (fd < 0) { perror("open"); exit(1); }
close(fd);

// flags:
//   O_RDONLY / O_WRONLY / O_RDWR
//   O_CREAT / O_EXCL / O_TRUNC / O_APPEND
//   O_NONBLOCK        非阻塞
//   O_CLOEXEC         exec 时自动关闭
//   O_SYNC / O_DSYNC   同步写
//   O_DIRECT          绕过页缓存

2. read / write

char buf[1024];
ssize_t n = read(fd, buf, sizeof(buf));     // 返回 0=EOF, -1=error
ssize_t w = write(fd, buf, n);             // 不一定一次写完

短读写处理:

ssize_t read_full(int fd, void *buf, size_t n) {
    char *p = buf;
    size_t left = n;
    while (left) {
        ssize_t r = read(fd, p, left);
        if (r < 0) { if (errno == EINTR) continue; return -1; }
        if (r == 0) break;
        p += r; left -= r;
    }
    return n - left;
}

3. lseek

off_t pos = lseek(fd, 0, SEEK_SET);    // 绝对
lseek(fd, 100, SEEK_CUR);              // 相对
lseek(fd, 0, SEEK_END);                // 到末尾

4. fcntl / ioctl

int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);

ioctl(fd, FIONREAD, &n);              // 看缓冲字节数
// 设备特定命令:ioctl(fd, BLKFLSBUF, 0); etc.

二、标准 I/O 库(stdio)

FILE *f = fopen("file", "r+");
fprintf(f, "x=%d\n", 42);
fscanf(f, "%d", &x);
fgets(buf, sizeof(buf), f);
size_t n = fread(buf, 1, 100, f);
fseek(f, 0, SEEK_END);
long pos = ftell(f);
fflush(f);
fclose(f);
FILE* fd
用户态有缓冲 内核无缓冲
fread/fwrite read/write
fopen open
标准 IO 效率高 raw IO 灵活

模式:r r+ w w+ a a+ b(b 在 Linux 无效)

三、缓冲设置

setvbuf(stdout, NULL, _IONBF, 0);   // 无缓冲(嵌入式常用)
setvbuf(fp, buf, _IOLBF, BUFSIZ);   // 行缓冲

四、内存映射(mmap)

#include <sys/mman.h>

int fd = open("data.bin", O_RDONLY);
void *p = mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
if (p == MAP_FAILED) { ... }
// 直接读写 *p 即可(无需 read/write)
munmap(p, length);
close(fd);

// 共享内存
int shm_fd = shm_open("/myregion", O_CREAT|O_RDWR, 0666);
ftruncate(shm_fd, size);
void *p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0);

优点:
- 减少内核/用户态拷贝
- 多进程共享简单
- 大文件访问性能好

五、高级 I/O

1. 多路复用(I/O 多路复用)

详见 08-socket.md

2. AIO(异步 IO)

3. io_uring(推荐)

struct io_uring ring;
io_uring_queue_init(32, &ring, 0);

struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd, buf, len, 0);
io_uring_submit(&ring);

struct io_uring_cqe *cqe;
io_uring_wait_cqe(&ring, &cqe);
// 处理 cqe->res
io_uring_cqe_seen(&ring, cqe);

4. splice / sendfile(零拷贝)

splice(fd_in, off_in, fd_out, off_out, len, flags);
sendfile(out_fd, in_fd, off, count);   // 把 in_fd 直接 send 到 out_fd

六、目录操作

#include <dirent.h>
DIR *d = opendir("/usr/lib");
struct dirent *e;
while ((e = readdir(d)) != NULL) {
    printf("%s\n", e->d_name);
}
closedir(d);

七、文件锁

1. flock(劝告锁)

flock(fd, LOCK_SH);   // 共享
flock(fd, LOCK_EX);   // 排他
flock(fd, LOCK_UN);   // 解锁

2. fcntl POSIX 锁

struct flock fl = {
    .l_type = F_WRLCK,
    .l_whence = SEEK_SET,
    .l_start = 0,
    .l_len = 0,           // 0 = 整个文件
};
fcntl(fd, F_SETLK, &fl);

八、嵌入式建议