博客
关于我
Linux 文件 IO
阅读量:581 次
发布时间:2019-03-11

本文共 2684 字,大约阅读时间需要 8 分钟。

Linux 文件操作详解

1. 引言

在 Linux 系统中,文件 I/O 是操作系统最基础的功能之一。程序与文件交互的方式主要有两种:文件 I/O标准 I/O。这两种方式各有特点,理解它们的区别对于高效编程至关重要。

1.1 文件 I/O

文件 I/O 是一种不带缓存的操作方式。每次调用 readwrite 时,都直接执行系统调用,操作速度非常快。这种方式不适合大量数据处理,因为频繁的系统调用会增加开销。

1.2 标准 I/O

标准 I/O 是 ANSI C 标准库中的实现,带有缓存机制。库函数如 fopenfclose 等会在需要时执行实际的文件操作,减少了系统调用的频率。适用于大部分常规文件操作。

2. 文件描述符

文件描述符是内核用来标识打开文件的关键结构。每个进程打开的文件都有一个唯一的描述符(非负整数)。以下是文件描述符的重要性和用法:

2.1 文件描述符的作用

  • 唯一标识:文件描述符唯一确定一个文件或设备。
  • 共享机制:多个进程可以共享同一个文件描述符,共享文件状态和当前位置。

2.2 标准输入、输出和错误

文件描述符的常用值:

  • 0:标准输入
  • 1:标准输出
  • 2:标准错误输出

这些值是 POSIX 标准定义的,通常由 <unistd.h> 中的宏定义表示。

3. 文件 I/O 相关系统调用

文件 I/O 的核心操作包括 openclosereadwritelseek。这些函数直接与内核交互,适合需要低延迟和高效率的场景。

3.1 open 函数

open 函数用于打开或创建文件,返回文件描述符。函数参数包括文件路径和操作模式。常见模式选项有:

  • O_RDONLY:只读模式
  • O_WRONLY:只写模式
  • O_RDWR:读写模式
  • O_CREAT:创建文件
  • O_TRUNC:截断文件
  • O_APPEND:追加模式

3.2 read 和 write 函数

  • read 从文件中读取数据,返回读取的字节数。
  • write 向文件中写入数据,返回写入的字节数。
  • 读写操作会更新文件描述符的当前位置。

3.3 lseek 函数

lseek 用于定位文件的当前位置,支持三种定位方式:

  • SEEK_SET:从文件开始位置
  • SEEK_CUR:从当前位置
  • SEEK_END:从文件末尾

3.4 文件空洞与稀疏文件

Linux 支持文件空洞(空文件中存在逻辑空隙),通过 lseek 定位到空洞位置后写入数据,中间的空洞部分读取时会返回 0。

4. 原子操作

为了保证文件操作的原子性,Linux 提供了 preadpwrite 函数。这些函数确保在定位和读写操作期间,其他进程无法干扰,避免数据竞争。

5. dup 和 dup2 函数

dupdup2 用于复制文件描述符。dup 返回当前可用最小的描述符,而 dup2 允许指定特定描述符,可能需要先关闭目标描述符。

5.1 dup 示例

int main() {    int fd = open("file.txt", O_RDWR);    int new_fd = dup(fd);    close(fd);    // new_fd 继续使用原文件}

5.2 dup2 示例

int main() {    int fd = open("file.txt", O_RDWR);    int new_fd = dup2(fd, 5);    close(5);    // new_fd 和 5 都指向同一文件}

6. fcntl 函数

fcntl 用于改变文件描述符的属性,包括文件状态标志和锁设置。常见用途包括设置非阻塞模式和获取文件状态。

6.1 例子

int main() {    int flags;    if (fcntl(STDIN_FILENO, F_GETFL) == -1) {        perror("fcntl F_GETFL");        exit(1);    }    flags |= O_NONBLOCK;    if (fcntl(STDIN_FILENO, F_SETFL, flags) == -1) {        perror("fcntl F_SETFL");        exit(1);    }    // 现在 STDIN_FILENO 是非阻塞的}

7. /dev/fd 目录

/dev/fd 提供了对标准输入、输出和错误的便捷访问。通过 /dev/fd/0 等路径,可以复制现有的文件描述符,避免了命令行特殊处理。

8. 统计目录文件数

通过 readdirlstat 函数,可以遍历目录并统计普通文件数量。递归处理子目录,并排除 ...

int count(char *root) {    DIR *dp = opendir(root);    if (dp == NULL) {        perror("opendir");        exit(1);    }    int n = 0;    while ((struct dirent *item = readdir(dp)) != NULL) {        if (strcmp(item->d_name, ".") == 0 || strcmp(item->d_name, "..") == 0) {            continue;        }        struct stat statbuf;        if (lstat(item->d_name, &statbuf) == -1) {            perror("lstat");            exit(1);        }        if (S_ISREG(statbuf.st_mode)) {            n++;        } else if (S_ISDIR(statbuf.st_mode)) {            n += count(item->d_name);        }    }    closedir(dp);    return n;}

9. 总结

文件 I/O 是 Linux 系统操作的核心,理解 openreadwrite 等函数的使用,能够有效地进行文件操作。通过合理使用文件描述符和同步机制,可以确保文件操作的高效和安全。

转载地址:http://ptavz.baihongyu.com/

你可能感兴趣的文章
Objective-C实现haversine distance斜距算法(附完整源码)
查看>>
Objective-C实现heap sort堆排序算法(附完整源码)
查看>>
Objective-C实现heap堆算法(附完整源码)
查看>>
Objective-C实现highest response ratio next高响应比优先调度算法(附完整源码)
查看>>
Objective-C实现hill climbing爬山法用来寻找函数的最大值算法(附完整源码)
查看>>
Objective-C实现histogram stretch直方图拉伸算法(附完整源码)
查看>>
Objective-C实现Hopcroft算法(附完整源码)
查看>>
Objective-C实现horizontal projectile motion平抛运动算法(附完整源码)
查看>>
Objective-C实现hornerMethod霍纳法算法(附完整源码)
查看>>
Objective-C实现Http Post请求(附完整源码)
查看>>
Objective-C实现http下载文件 (附完整源码)
查看>>
Objective-C实现Http协议下载文件(附完整源码)
查看>>
Objective-C实现huffman哈夫曼编码算法(附完整源码)
查看>>
Objective-C实现ID3贪心算法(附完整源码)
查看>>
Objective-C实现IIR 滤波器算法(附完整源码)
查看>>
Objective-C实现IIR数字滤波器(附完整源码)
查看>>
Objective-C实现insertion sort插入排序算法(附完整源码)
查看>>
Objective-C实现integer partition整数分区算法(附完整源码)
查看>>
Objective-C实现integerPartition整数划分算法(附完整源码)
查看>>
Objective-C实现interpolation search插值搜索算法(附完整源码)
查看>>