1. 文件定位接口 lseek
1.1 为什么需要 lseek
在文件读写过程中,文件指针(光标)会随着 read 或 write 操作自动移动。
- 读后写:读完文件后,指针在末尾,直接写入会追加内容,符合预期。
- 写后读:写入一行内容后,指针位于写入内容的末尾。如果此时想读取刚才写入的内容,由于指针不在开头,直接读取会失败(读不到数据)。
- 解决方案:需要使用
lseek函数手动移动文件读写指针到指定位置。
1.2 函数原型
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
1.3 参数详解
fd:文件描述符。offset:偏移量,表示移动的字节数(可以是负数)。whence:参考位置,决定从何处开始计算偏移量。SEEK_SET:从文件开头开始计算。新位置 = 文件开头 +offset。SEEK_CUR:从当前位置开始计算。新位置 = 当前位置 +offset。SEEK_END:从文件末尾开始计算。新位置 = 文件末尾 +offset。
1.4 返回值
- 成功:返回新的文件读写位置(距离文件开头的字节数)。
- 失败:返回
-1。
1.5 常用使用场景
- 重置指针到文件开头:
lseek(fd, 0, SEEK_SET); - 移动指针到文件末尾(用于追加写入):
lseek(fd, 0, SEEK_END); - 获取当前指针位置:
偏移量设为 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 参数详解
path:文件路径字符串。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) 打开。 - 步骤:
- 调用
chmod("filename", 0200)修改权限。 - 检查返回值,若
< 0则修改失败。 - 调用
open("filename", O_RDONLY)。 - 由于权限不足,
open将失败,返回-1。 - 再次调用
chmod("filename", 0664)恢复权限。 - 再次
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);