文件IO:文件定位、权限修改

文件IO:文件定位、权限修改

1. 文件定位接口 lseek

1.1 为什么需要 lseek

在文件读写过程中,文件指针(光标)会随着 readwrite 操作自动移动。

  • 读后写:读完文件后,指针在末尾,直接写入会追加内容,符合预期。
  • 写后读:写入一行内容后,指针位于写入内容的末尾。如果此时想读取刚才写入的内容,由于指针不在开头,直接读取会失败(读不到数据)。
  • 解决方案:需要使用 lseek 函数手动移动文件读写指针到指定位置。

1.2 函数原型

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

1.3 参数详解

  1. fd:文件描述符。
  2. offset:偏移量,表示移动的字节数(可以是负数)。
  3. whence:参考位置,决定从何处开始计算偏移量。
    • SEEK_SET:从文件开头开始计算。新位置 = 文件开头 + offset
    • SEEK_CUR:从当前位置开始计算。新位置 = 当前位置 + offset
    • SEEK_END:从文件末尾开始计算。新位置 = 文件末尾 + offset

1.4 返回值

  • 成功:返回新的文件读写位置(距离文件开头的字节数)。
  • 失败:返回 -1

1.5 常用使用场景

  1. 重置指针到文件开头
    lseek(fd, 0, SEEK_SET);
    
  2. 移动指针到文件末尾(用于追加写入):
    lseek(fd, 0, SEEK_END);
    
  3. 获取当前指针位置
    偏移量设为 0,参考位置设为 SEEK_CUR,不移动指针,仅返回当前位置。
    off_t current_pos = lseek(fd, 0, SEEK_CUR);
    

1.6 代码演示与注意事项

  • 指针移动验证

    • open 文件时,指针位置为 0
    • read 读取 10 个字节后,指针位置变为 10
    • write 写入 3 个字节后,指针位置变为 13
  • 覆盖写入风险

    • 如果指针未移动到文件末尾空白处直接写入,会覆盖原有内容。
    • 例如:在位置 10 写入 "AAA",会覆盖原文件该位置的 3 个字符。
    • 建议:若要追加内容而不破坏原文件,应先 lseek(fd, 0, SEEK_END)
  • 读取整个文件

    • lseek(fd, 0, SEEK_SET) 回到开头。
    • 使用 while 循环配合 read 读取,直到 read 返回 0(表示读到文件末尾 EOF)。
  • 缓冲区清理

    • 使用 printf("%s", buf) 打印读取内容时,若缓冲区未清空,可能打印出上次残留的垃圾数据。
    • 解决:每次读取前使用 bzero(buf, sizeof(buf)) 清空缓冲区。
    #include <strings.h>
    bzero(buf, sizeof(buf));
    

2. 修改文件权限 chmod

2.1 为什么需要 chmod

  • open 函数打开文件时,若文件权限不足(如只有写权限却尝试以读方式打开),会导致打开失败。
  • 有时需要在代码中动态修改文件权限,以便后续进行读写操作,或在操作完成后限制权限。

2.2 函数原型

#include <sys/stat.h>

int chmod(const char *path, mode_t mode);

2.3 参数详解

  1. path:文件路径字符串。
  2. mode:新的权限值。
    • 八进制表示法:如 0664 (rw-rw-r--),0200 (只写)。
    • 宏定义表示法:需结合位运算,如 S_IRUSR | S_IWUSR
    • 权限位说明(八进制):
      • 第一位:特殊权限(通常设为 0)。
      • 第二位:所有者权限 (User)。
      • 第三位:所属组权限 (Group)。
      • 第四位:其他用户权限 (Others)。
      • 数值:4 (读 r), 2 (写 w), 1 (执行 x)。

2.4 返回值

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

2.5 代码演示

  • 场景:修改文件权限为只写 (0200),然后尝试以只读 (O_RDONLY) 打开。
  • 步骤
    1. 调用 chmod("filename", 0200) 修改权限。
    2. 检查返回值,若 < 0 则修改失败。
    3. 调用 open("filename", O_RDONLY)
    4. 由于权限不足,open 将失败,返回 -1
    5. 再次调用 chmod("filename", 0664) 恢复权限。
    6. 再次 open,此时可成功打开。
  • 注意chmod 应在 open 之前调用。若文件已打开,修改权限可能不会立即影响已打开的文件描述符,且操作的是磁盘上的文件节点。

3. 关键代码片段总结

3.1 lseek 读取整个文件

// 回到文件开头
lseek(fd, 0, SEEK_SET);

// 循环读取
char buf[20] = {0};
int ret = 0;
while ((ret = read(fd, buf, sizeof(buf))) > 0) {
    bzero(buf, sizeof(buf)); // 清空缓冲区,防止打印乱码
    // 注意:实际打印应只打印 ret 个字节,或者确保 buf 以 '\0' 结尾
    // 此处演示中为了简单直接打印,但严谨做法是处理 ret 长度
    printf("%s", buf); 
}
if (ret == 0) {
    printf("Read end\n");
}

3.2 chmod 权限修改

#include <sys/stat.h>

// 修改为只写权限 (0200)
if (chmod(argv[1], 0200) < 0) {
    perror("chmod error");
    return -1;
}

// 尝试打开
int fd = open(argv[1], O_RDONLY);
if (fd == -1) {
    printf("Open error (Permission denied)\n");
}

// 恢复权限
chmod(argv[1], 0664);
文件IO:读写 2026-02-25
标准IO:缓存机制 2026-02-26

评论区