Linux下,文件I/O是操作系统与文件系统之间进行数据传输的关键部分。文件I/O操作允许程序读取和写入文件,管理文件的打开、关闭、创建和删除等操作。
1. 文件描述符
在Linux中,每个打开的文件都由一个文件描述符来表示。文件描述符是一个非负整数,通常从0开始,分别表示标准输入stdin、标准输出stdout和标准错误stderr。用户程序打开文件后,操作系统会为其分配一个文件描述符。
2. 文件操作函数
Linux提供了一系列的系统调用和库函数来进行文件操作,主要包括:
-
打开文件:
-
open()
: 打开文件并返回文件描述符。
int fd = open("filename", O_RDONLY);
-
-
读取文件:
-
read()
: 从文件中读取数据。
ssize_t bytes_read = read(fd, buffer, count);
-
-
写入文件:
-
write()
: 向文件中写入数据。
ssize_t bytes_written = write(fd, buffer, count);
-
-
关闭文件:
-
close()
: 关闭打开的文件描述符。
close(fd);
-
-
文件状态信息:
fstat()
: 获取文件的状态信息。stat()
: 获取文件的状态信息(用于路径名)。
3. 文件打开模式
在使用open()
函数时,可以指定不同的文件打开模式
O_RDONLY
: 只读模式。O_WRONLY
: 只写模式。O_RDWR
: 读写模式。O_CREAT
: 如果文件不存在则创建文件。O_TRUNC
: 如果文件存在并以写入模式打开,则将其截断为零长度。O_APPEND
: 以追加模式打开文件。
4. 文件I/O缓冲
Linux使用缓冲区来提高文件I/O的效率。标准库函数如fread()
、fwrite()
通常会使用缓冲I/O,而系统调用如read()
、write()
则直接与内核进行交互。缓冲区的使用可以减少系统调用的次数,从而提高性能。
5. 文件锁定
在多进程或多线程环境中,文件锁定机制可以防止多个进程同时写入同一个文件,导致数据不一致。常用的文件锁定方法包括
- 共享锁(read lock):允许多个进程同时读取文件。
- 独占锁(write lock):只允许一个进程写入文件。
可以使用flock()
或fcntl()
进行文件锁定。
6. 目录操作
除了普通文件,Linux还支持目录操作。常用的目录操作函数包括:
opendir()
: 打开目录。readdir()
: 读取目录中的条目。closedir()
: 关闭目录。
7. 文件权限与所有权
Linux文件系统具有严格的权限控制。每个文件都有所有者、组和其他用户的权限,可以通过chmod
、chown
等命令进行管理。
8. 文件系统
Linux支持多种文件系统,如ext4、XFS、Btrfs等。每种文件系统都有其特定的特点和优缺点,适合不同的使用场景。
9. 异步I/O
Linux还支持异步I/O(AIO),允许程序在进行I/O操作时继续执行其他任务,而不必等待I/O操作完成。可以使用aio_read()
和aio_write()
函数实现异步I/O。
例子1. 文件的创建与写入
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
int fd;
const char *text = "Hello, Linux File I/O!\n";
// 创建并打开文件
fd = open("example.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (fd == -1) {
perror("Error opening file");
return 1;
}
// 写入数据
write(fd, text, strlen(text));
// 关闭文件
close(fd);
return 0;
}
例子2. 文件的读取
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd;
char buffer[100];
ssize_t bytesRead;
// 打开文件
fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Error opening file");
return 1;
}
// 读取数据
bytesRead = read(fd, buffer, sizeof(buffer) - 1);
if (bytesRead == -1) {
perror("Error reading file");
close(fd);
return 1;
}
// 添加字符串结束符
buffer[bytesRead] = '\0';
// 打印读取的数据
printf("Read from file: %s", buffer);
// 关闭文件
close(fd);
return 0;
}
例子3. 追加写入文件
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
int fd;
const char *text = "Appending this line.\n";
// 以追加模式打开文件
fd = open("example.txt", O_WRONLY | O_APPEND);
if (fd == -1) {
perror("Error opening file");
return 1;
}
// 追加写入数据
write(fd, text, strlen(text));
// 关闭文件
close(fd);
return 0;
}
例子4. 目录操作示例
#include <stdio.h>
#include <dirent.h>
int main() {
DIR *dir;
struct dirent *entry;
// 打开当前目录
dir = opendir(".");
if (dir == NULL) {
perror("Error opening directory");
return 1;
}
// 读取目录项
while ((entry = readdir(dir)) != NULL) {
printf("Found file: %s\n", entry->d_name);
}
// 关闭目录
closedir(dir);
return 0;
}
例子5. 文件锁定示例
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
int fd;
struct flock lock;
// 打开文件
fd = open("example.txt", O_WRONLY);
if (fd == -1) {
perror("Error opening file");
return 1;
}
// 初始化锁
lock.l_type = F_WRLCK; // 写锁
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // 锁定整个文件
// 加锁
if (fcntl(fd, F_SETLK, &lock) == -1) {
perror("Error locking file");
close(fd);
return 1;
}
// 写入数据
const char *text = "This is a locked write.\n";
write(fd, text, strlen(text));
// 解锁
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock);
// 关闭文件
close(fd);
return 0;
}