应用——文件I/O操作代码

文件I/O操作代码分析

一、基础文件操作

1. 打开文件 - 01open.c

cpp 复制代码
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    int fd = open("1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    if (-1 == fd) {
        fprintf(stderr, "open error\n");
        return 1;
    }
    return 0;
}

知识点

  • open():系统调用打开文件

  • flags参数

    • O_WRONLY:只写模式

    • O_CREAT:文件不存在时创建

    • O_TRUNC:清空文件内容

  • mode参数0666表示文件权限(用户、组、其他都可读写)

  • 文件描述符:成功返回非负整数,失败返回-1

2. 写入文件 - 04write.c

cpp 复制代码
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    int fd = open("1.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    char str[100] = "hello";
    ssize_t ret = write(fd, str, strlen(str));
    printf("写入了%ld字节到文件", ret);
    close(fd);
    return 0;
}

知识点

  • write(fd, buf, count):写入数据

  • strlen(str) vs sizeof(str)

    • strlen(str):实际字符串长度(不包括'\0')

    • sizeof(str):数组总大小(100字节)

  • ssize_t:有符号整数类型,表示实际写入字节数

  • 必须调用close(fd)释放资源

3. 读取文件 - 05read.c

cpp 复制代码
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    int fd = open("/etc/passwd", O_RDONLY);
    char buf[50] = {0};
    while (1) {
        bzero(buf, sizeof(buf)); // 清空缓冲区
        int ret = read(fd, buf, sizeof(buf)-1); // 留一个位置给'\0'
        if (ret <= 0) break;
        printf("[%d]:{%s}", ret, buf);
    }
    close(fd);
    return 0;
}

知识点

  • read(fd, buf, count):读取数据

  • 缓冲区清空

    • bzero(buf, sizeof(buf)):将内存清零

    • memset(buf, 0, sizeof(buf)):功能相同

  • 读取策略sizeof(buf)-1保留一个字节给字符串结束符

  • 返回值

    • >0:实际读取字节数

    • =0:文件结束

    • <0:错误

4. 文件复制 - 06read_cp.c

cpp 复制代码
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    if (argc < 3) {
        printf("usage: ./a.out srcfile dstfile\n");
    }
    int fd_src = open(argv[1], O_RDONLY);
    int fd_dst = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0666);
    
    while (1) {
        char buffer[1024] = {0};
        int ret = read(fd_src, buffer, sizeof(buffer));
        if (ret <= 0) break;
        write(fd_dst, buffer, ret);
    }
    close(fd_dst);
    close(fd_src);
    return 0;
}

知识点

  • 命令行参数argv[1]源文件,argv[2]目标文件

  • 分块读取:循环读取直到文件结束

  • 精确写入write(fd_dst, buffer, ret)只写入实际读取的字节

  • 资源管理:最后关闭两个文件描述符

二、高级文件操作

1. 文件插入 - 02insert_file.c

cpp 复制代码
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    FILE* fp = fopen("1.txt", "r+");
    
    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    long size = ftell(fp);
    
    int pos = 15;
    char insert_str[100] = "hello";
    
    // 保存后半部分内容
    fseek(fp, pos, SEEK_SET);
    char *data = (char*)malloc(size);
    fread(data, size-pos, 1, fp);
    
    // 插入内容
    fseek(fp, pos, SEEK_SET);
    fwrite(insert_str, strlen(insert_str), 1, fp);
    fwrite(data, size-pos, 1, fp);
    
    fclose(fp);
    free(data);
    return 0;
}

知识点

  • 标准I/O :使用fopen()fread()fwrite()

  • 文件定位

    • fseek(fp, 0, SEEK_END):移动到文件末尾

    • ftell(fp):获取当前位置(即文件大小)

  • 插入策略

    1. 读取插入点之后的内容到内存

    2. 在插入点写入新内容

    3. 追加原来的后半部分内容

  • 内存管理 :使用malloc()动态分配,最后free()

2. 文件定位 - 08lseek.c

cpp 复制代码
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    int fd = open("1.txt", O_RDWR);
    
    // 获取文件大小
    long size = lseek(fd, 0, SEEK_END);
    printf("size %ld\n", size);
    
    // 移动到指定位置并写入
    lseek(fd, 1024*1024, SEEK_SET);
    char str[] = "老孙到此一游";
    write(fd, str, strlen(str));
    
    close(fd);
    return 0;
}

知识点

  • lseek(fd, offset, whence):移动文件指针

    • SEEK_SET:从文件开头

    • SEEK_CUR:从当前位置

    • SEEK_END:从文件末尾

  • 空洞文件:跳过大量字节后写入,中间部分会被填'\0'

  • 文件大小 :使用lseek(fd, 0, SEEK_END)获取文件大小

三、标准输入输出

07stdin.c

cpp 复制代码
#include <fcntl.h>
#include <stdio.h>
int main(int argc, char **argv)
{
    char buf[10] = {0};
    printf("pls input num:");
    fflush(stdout); // 强制刷新缓冲区
    read(0, buf, sizeof(buf)); // 从标准输入读取
    int num = atoi(buf);
    write(2, &num, 4); // 写入标准错误
    return 0;
}

知识点

  • 标准文件描述符

    • 0:标准输入(stdin)

    • 1:标准输出(stdout)

    • 2:标准错误(stderr)

  • 缓冲机制

    • printf()输出到缓冲区,需要刷新才能显示

    • fflush(stdout)强制刷新输出缓冲区

  • 字符串转换atoi()将字符串转换为整数

  • 系统调用读写read()/write()也可以操作标准输入输出

四、应用实例

字典程序 - 03dict.c

cpp 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "list.h"
typedef struct {
    char word[50];
    char mean[512];
    struct list_head node;
} DATATYPE;

int main(int argc, char** argv)
{
    // 1. 打开字典文件
    FILE* fp = fopen("/home/linux/dict.txt", "r");
    
    // 2. 初始化链表
    struct list_head dict_head;
    INIT_LIST_HEAD(&dict_head);
    
    // 3. 读取并存储字典数据
    while (1) {
        char str[1024] = {0};
        if (NULL == fgets(str, sizeof(str), fp)) break;
        
        char* word = strtok(str, " ");
        char* mean = strtok(NULL, "\r");
        add_word(&dict_head, word, mean);
    }
    
    // 4. 用户查询交互
    while (1) {
        char want_word[50] = {0};
        printf("pls input want_word:");
        fgets(want_word, sizeof(want_word), stdin);
        want_word[strlen(want_word) - 1] = '\0'; // 去掉换行符
        
        if (0 == strcmp(want_word, "#quit")) break;
        
        DATATYPE* tmp = find_word(&dict_head, want_word);
        if (NULL == tmp) {
            printf("cant find word:%s\n", want_word);
        } else {
            printf("word:%s mean:%s\n", tmp->word, tmp->mean);
        }
    }
    return 0;
}
复制代码

核心知识点

  1. 文件读取

    • fgets(str, sizeof(str), fp):安全读取一行

    • 检查NULL判断文件结束// 原始格式:单词 解释\r\n

复制代码
char* word = strtok(str, " ");    // 第一个空格前是单词
char* mean = strtok(NULL, "\r");  // 到\r前是解释
fgets(want_word, sizeof(want_word), stdin);
复制代码
want_word[strlen(want_word) - 1] = '\0'; // 去掉末尾的换行符
  1. 链表操作

    • list_add(&p->node, head):添加到链表

    • list_for_each_entry_safe():安全遍历链表

五、重要总结

1. 系统调用 vs 标准I/O

操作 系统调用 标准I/O
打开 open() fopen()
读取 read() fread()
写入 write() fwrite()
关闭 close() fclose()
定位 lseek() fseek()

2. 常用文件打开模式

模式 说明
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_CREAT 不存在时创建
O_TRUNC 清空文件
O_APPEND 追加模式

3. 错误处理模式

复制代码
int fd = open("file.txt", O_RDONLY);
if (-1 == fd) {
    perror("open failed");  // 自动添加错误信息
    // 或
    fprintf(stderr, "open error: %s\n", strerror(errno));
    return 1;
}

4. 内存与文件操作注意事项

  1. 缓冲区管理:读取前清空,写入时注意长度

  2. 资源释放:打开后必须关闭,分配后必须释放

  3. 错误检查:每个系统调用都可能失败

  4. 边界检查:防止缓冲区溢出

  5. 文件权限:创建文件时指定合适的权限

相关推荐
未来之窗软件服务3 小时前
幽冥大陆(四十五)人工智能自动化交互系统ASR——东方仙盟筑基期
运维·自动化·asr·仙盟创梦ide·东方仙盟·东方仙盟sdk·东方仙盟自动化
Hui Baby3 小时前
Python Flask 多文件项目打包部署(Linux+Docker+Windows 全环境)
linux·python·flask
石像鬼₧魂石3 小时前
适合渗透测试学习的网络靶场
网络·学习
物随心转3 小时前
Arm的协处理器
linux·arm开发
sealaugh323 小时前
AI(学习笔记第十五课)从langchain的v0.3到v1.0
人工智能·笔记·学习
发疯幼稚鬼3 小时前
d-堆,左式堆及斜堆的简单介绍
算法
不会代码的小猴3 小时前
C++的第十三天笔记
c++·笔记·算法
麦麦在写代码3 小时前
前端学习6(JS 1)
前端·javascript·学习
小婷要努力3 小时前
Linux常用命令速查表
linux·运维·服务器