C语言基础:7.3系统级IO与错误处理

【系统编程】POSIX文件操作与健壮性编程

一、系统调用与标准库对比

1. 核心接口差异

/* 标准库文件操作 */
FILE *fp = fopen("file.txt", "r");
fread(buffer, 1, size, fp);
fclose(fp);

/* 系统级文件操作 */
int fd = open("file.txt", O_RDONLY);
read(fd, buffer, size);
close(fd);

2. 性能特性对比

特性标准I/O系统I/O
缓冲机制自动管理缓冲区无缓冲
线程安全需要自行保证
错误处理通过返回值+errno直接返回错误码
文件控制粒度中等精细控制

二、系统调用深度解析

1. open接口规范

// 安全打开文件模板
int open_file(const char *path, int flags, mode_t mode) {
    int fd = open(path, flags, mode);
    if (fd == -1) {
        fprintf(stderr, "[%s] 打开失败: ", path);
        perror("");
        exit(EXIT_FAILURE);
    }
    return fd;
}

// 典型使用场景
int src_fd = open_file("data.bin", O_RDONLY, 0);
int dst_fd = open_file("backup.bin", 
                      O_WRONLY | O_CREAT | O_TRUNC,
                      S_IRUSR | S_IWUSR); // 600权限

2. 读写操作安全模式

ssize_t safe_read(int fd, void *buf, size_t count) {
    ssize_t total = 0;
    while (total < count) {
        ssize_t n = read(fd, buf + total, count - total);
        if (n == -1) {
            if (errno == EINTR) continue; // 处理信号中断
            return -1;
        }
        if (n == 0) break; // EOF
        total += n;
    }
    return total;
}

ssize_t safe_write(int fd, const void *buf, size_t count) {
    ssize_t total = 0;
    while (total < count) {
        ssize_t n = write(fd, buf + total, count - total);
        if (n == -1) {
            if (errno == EINTR) continue;
            return -1;
        }
        total += n;
    }
    return total;
}

三、文件拷贝工具实现

1. 核心架构设计

#define BUF_SIZE 65536 // 64KB缓冲区

void copy_file(const char *src, const char *dst) {
    int src_fd = open(src, O_RDONLY);
    if (src_fd == -1) {
        perror("打开源文件失败");
        exit(EXIT_FAILURE);
    }

    int dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 
                      S_IRUSR | S_IWUSR);
    if (dst_fd == -1) {
        perror("创建目标文件失败");
        close(src_fd);
        exit(EXIT_FAILURE);
    }

    char buffer[BUF_SIZE];
    ssize_t bytes_read;

    while ((bytes_read = safe_read(src_fd, buffer, BUF_SIZE)) > 0) {
        if (safe_write(dst_fd, buffer, bytes_read) != bytes_read) {
            perror("写入失败");
            break;
        }
    }

    if (bytes_read == -1) {
        perror("读取失败");
    }

    close(src_fd);
    close(dst_fd);
}

2. 高级特性扩展

// 带进度显示的文件拷贝
void copy_with_progress(const char *src, const char *dst) {
    struct stat st;
    if (stat(src, &st) == -1) {
        perror("获取文件信息失败");
        exit(EXIT_FAILURE);
    }

    off_t total_size = st.st_size;
    off_t copied = 0;

    // ...打开文件操作同上...

    while ((bytes_read = safe_read(src_fd, buffer, BUF_SIZE)) > 0) {
        ssize_t written = safe_write(dst_fd, buffer, bytes_read);
        if (written != bytes_read) {
            perror("写入失败");
            break;
        }
        copied += written;
        printf("进度: %.2f%%\r", 
              (double)copied / total_size * 100);
    }

    printf("\n拷贝完成,总计拷贝: %ld MB\n", 
          copied / 1024 / 1024);
}

四、错误处理最佳实践

1. 错误码分类处理

void handle_io_error(const char *operation) {
    switch(errno) {
        case EACCES:
            fprintf(stderr, "权限不足: %s\n", operation);
            break;
        case ENOENT:
            fprintf(stderr, "文件不存在: %s\n", operation);
            break;
        case ENOSPC:
            fprintf(stderr, "磁盘空间不足: %s\n", operation);
            break;
        default:
            perror(operation);
    }
    exit(EXIT_FAILURE);
}

// 使用示例
int fd = open("file", O_RDONLY);
if (fd == -1) {
    handle_io_error("打开文件");
}

2. 资源安全释放模式

void guarded_copy(const char *src, const char *dst) {
    int src_fd = -1, dst_fd = -1;

    src_fd = open(src, O_RDONLY);
    if (src_fd == -1) goto error;

    dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0600);
    if (dst_fd == -1) goto error;

    // ...拷贝逻辑...

    close(src_fd);
    close(dst_fd);
    return;

error:
    if (src_fd != -1) close(src_fd);
    if (dst_fd != -1) close(dst_fd);
    handle_io_error("文件操作");
}

核心知识点总结

  1. 系统I/O关键点

    • 文件描述符是整型资源
    • 必须显式管理缓冲区
    • 需要处理中断和部分读写
  2. 错误处理原则

    • 每次系统调用后检查返回值
    • 区分暂时性错误(如EINTR)
    • 使用goto集中处理资源释放
  3. 性能优化方向

    • 调整缓冲区大小(64KB-1MB)
    • 使用O_DIRECT绕过页缓存
    • 多线程分块拷贝

调试技巧

  1. 使用strace追踪系统调用:

    strace -e trace=open,read,write ./copy src dst
    
  2. 查看错误码对应描述:

    printf("Error %d: %s\n", errno, strerror(errno));
    
  3. 验证文件完整性:

    md5sum src_file dst_file
    

扩展学习方向

  1. 异步I/O(aio_read/aio_write)
  2. 内存映射文件(mmap)
  3. 文件锁(fcntl/F_SETLK)
  4. 事件驱动I/O(select/poll/epoll)
  5. 零拷贝技术(splice/sendfile)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵鑫亿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值