代码示例:5.1.4 open/read/write/lseek 与 errno
全部示例均标注编译命令、适用环境与实测状态;完整验证记录见《03.5-代码编译运行验证记录》。
examples/ex1-open-read.c · mycp:open/read/write 最小文件拷贝
/* ex1-open-read.c —— open/read/write 最小文件拷贝(mycp) * 适用环境:Linux(推荐);Windows 下用 MinGW-w64 的 POSIX 兼容层可编译运行 * 标准:POSIX(C99 亦可) 编译:gcc ex1-open-read.c -o mycp -Wall -Wextra * 运行:./mycp 源文件 目标文件 * 【平台差异】Windows CRT 的文件描述符默认是"文本模式",写文件会把 \n 转成 \r\n, * 必须加 O_BINARY 才是纯二进制拷贝;Linux 没有文本/二进制之分,O_BINARY 不存在。 */ #include <stdio.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #ifdef _WIN32 #define O_BIN O_BINARY /* MinGW-w64 提供的二进制模式标志 */ #else #define O_BIN 0 /* Linux 下无此标志 */ #endif #define BUF_SIZE 1024 int main(int argc, char *argv[]) { if (argc != 3) { fprintf(stderr, "用法: %s <源文件> <目标文件>\n", argv[0]); return 1; } int fd_in = open(argv[1], O_RDONLY | O_BIN); if (fd_in < 0) { fprintf(stderr, "open %s 失败: %s (errno=%d)\n", argv[1], strerror(errno), errno); return 1; } /* O_CREAT:不存在则创建;O_TRUNC:存在则截断;0644 受 umask 影响 */ int fd_out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC | O_BIN, 0644); if (fd_out < 0) { fprintf(stderr, "open %s 失败: %s (errno=%d)\n", argv[2], strerror(errno), errno); close(fd_in); return 1; } char buf[BUF_SIZE]; ssize_t n; while ((n = read(fd_in, buf, sizeof(buf))) > 0) { ssize_t off = 0; while (off < n) { /* 处理"部分写" */ ssize_t w = write(fd_out, buf + off, (size_t)(n - off)); if (w < 0) { fprintf(stderr, "write 失败: %s (errno=%d)\n", strerror(errno), errno); close(fd_in); close(fd_out); return 1; } off += w; } } if (n < 0) { /* read 出错(不是 EOF) */ fprintf(stderr, "read 失败: %s (errno=%d)\n", strerror(errno), errno); close(fd_in); close(fd_out); return 1; } if (close(fd_in) < 0 || close(fd_out) < 0) { fprintf(stderr, "close 失败: %s (errno=%d)\n", strerror(errno), errno); return 1; } printf("拷贝完成: %s -> %s\n", argv[1], argv[2]); return 0; }examples/ex2-lseek-hole.c · lseek 制造空洞文件
/* ex2-lseek-hole.c —— 用 lseek 制造空洞文件 * 适用环境:Linux(推荐);Windows 下用 MinGW-w64 的 POSIX 兼容层可编译验证语法 * 编译:gcc ex2-lseek-hole.c -o hole -Wall -Wextra * 运行:./hole hole.dat(随后可用 ls -l 与 du 对比观察"稀疏文件"现象——Linux 专属行为) */ #include <stdio.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { if (argc != 2) { fprintf(stderr, "用法: %s <文件>\n", argv[0]); return 1; } int fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { perror("open"); return 1; } if (write(fd, "Hello", 5) != 5) { perror("write"); close(fd); return 1; } /* lseek 修改文件偏移量:对随后的 write 同样生效(本章【纠错】err-7.1-1) */ off_t pos = lseek(fd, 1024 * 1024, SEEK_SET); /* 跳到 1MB 处 */ if (pos < 0) { perror("lseek"); close(fd); return 1; } printf("lseek 后文件偏移 = %lld\n", (long long)pos); if (write(fd, "End", 3) != 3) { perror("write"); close(fd); return 1; } off_t end = lseek(fd, 0, SEEK_CUR); /* 取当前偏移 */ printf("当前偏移 = %lld(= 文件逻辑大小,中间 1MB-5B 为空洞)\n", (long long)end); if (close(fd) < 0) { perror("close"); return 1; } return 0; }examples/ex3-errno-handling.c · errno/perror/strerror 错误处理演示
/* ex3-errno-handling.c —— 出错路径与 errno/perror/strerror * 适用环境:Linux / Windows(MinGW) * 编译:gcc ex3-errno-handling.c -o errdemo -Wall -Wextra * 运行:./errdemo 一个不存在的文件 */ #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> int main(int argc, char *argv[]) { const char *path = (argc > 1) ? argv[1] : "/no/such/file.txt"; int fd = open(path, O_RDONLY); if (fd < 0) { printf("open(\"%s\") 失败:\n", path); printf(" errno = %d\n", errno); printf(" strerror = %s\n", strerror(errno)); perror(" perror "); printf(" 规则: errno 只在出错时才有意义;任何成功调用都不会清零它;\n"); printf(" errno.h 中的常量名必须写对,例如 EACCES(不是 EACCESS)。\n"); return 1; } close(fd); return 0; }