linux下文件读写操作
Linux下,文件I/O是操作系统与文件系统之间进行数据传输的关键部分。文件I/O操作允许程序读取和写入文件,管理文件的打开、关闭、创建和删除等操作。
1. 文件描述符
在Linux中,每个打开的文件都由一个文件描述符来表示。文件描述符是一个非负整数,通常从0开始,分别表示标准输入stdin、标准输出stdout和标准错误stderr。用户程序打开文件后,操作系统会为其分配一个文件描述符。
2. 文件操作函数
Linux提供了一系列的系统调用和库函数来进行文件操作,主要包括:
-  打开文件 -  open()打开文件并返回文件描述符。文件描述符是进程访问文件的句柄,后续的 read()和write()操作都需要通过它进行。int fd = open("filename", O_RDONLY);
 
-  
-  读取文件 -  read()从文件中读取数据。 char buf[1024]; ssize_t bytes_read = read(fd, buf, sizeof(buf));- 流程 
      - 进程调用read(),请求从文件中读取数据。
- 内核检查页缓存中是否存在请求的数据 
        - 如果数据在页缓存中,内核将数据从页缓存复制到用户空间的缓冲区。
- 如果数据不在页缓存中,内核会从磁盘读取数据到页缓存,然后再复制到用户空间。
 
- 返回实际读取的字节数。
 
- 进程调用
 
- 流程 
      
 
-  
-  写入文件 -  write()向文件中写入数据。 const char *text = "Hello, world!"; ssize_t bytes_written = write(fd, text, 13);- 流程 
      - 进程调用write(),请求将数据写入文件。
- 内核将数据从用户空间复制到页缓存中。
- 数据被标记为“脏页”,表示需要写回磁盘。
- 内核的页回写机制会在适当的时候将脏页写回磁盘。
 
- 进程调用
 
- 流程 
      
 
-  
-  页缓存的作用 - 页缓存是内核维护的一块内存区域,用于缓存文件数据。
- 作用 
    - 减少磁盘I/O:通过缓存文件数据,减少对磁盘的直接访问,提高性能。
- 延迟写入:write()操作不会立即将数据写入磁盘,而是先写入页缓存,由内核在后续的某个时间点写回磁盘。
- 预读机制:内核会提前读取文件数据到页缓存中,优化后续的read()操作。
 
 
-  关闭文件 -  close()使用 close()系统调用关闭文件,释放文件描述符。close(fd);
 
-  
-  文件状态信息 - fstat(): 获取文件的状态信息。
- stat(): 获取文件的状态信息(用于路径名)。
 
-  页回写机制 - 内核会在以下情况下将脏页写回磁盘 
    - 页缓存中的脏页达到一定比例。
- 进程调用fsync()或fdatasync()强制刷新页缓存。
- 系统内存不足时,内核会回收脏页。
 
 
- 内核会在以下情况下将脏页写回磁盘 
    
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;
}
在Linux中,如果要对其他目录中的文件进行I/O操作,只需在文件路径中指定完整的路径名。
1. 在其他目录中创建和写入文件
假设你想在/tmp目录下创建一个文件并写入数据,可以这样做:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
    int fd;
    const char *text = "Hello, Linux File I/O in /tmp!\n";
    // 创建并打开/tmp目录下的文件
    fd = open("/tmp/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. 从其他目录读取文件
如果要从/tmp目录读取文件,可以使用类似的方式:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
    int fd;
    char buffer[100];
    ssize_t bytesRead;
    // 打开/tmp目录下的文件
    fd = open("/tmp/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. 追加写入其他目录的文件
如果需要在/tmp/example.txt中追加数据,可以这样操作:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int main() {
    int fd;
    const char *text = "Appending this line to /tmp/example.txt.\n";
    // 以追加模式打开/tmp目录下的文件
    fd = open("/tmp/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. 处理文件路径中的空格和特殊字符
如果文件路径中包含空格或特殊字符,可以使用转义字符或用引号括起来。例如:
// 假设文件路径为 "/tmp/my file.txt"
fd = open("/tmp/my\\ file.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
或者:
fd = open("\"/tmp/my file.txt\"", O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
