【Linux】Linux文件I/O

简介: 【Linux】Linux文件I/O

文件I/O

直接使用系统调用的缺点:

  1. 影响系统性能

系统调用比普通函数调用开销大,因为系统调用要进行用户空间和内核空间的切换。

  1. 系统调用一次所能读写的数据量大小,受硬件的限制。

解决方案:使用带缓冲功能的标准I/O库,以减少系统调用的次数。

例如: fwrite、fread、fopen、fclose、fseek、fflush


文件系统接口

文件系统——一种把数据组织成文件和目录的存储方式,提供了基于文件的存取接口,并通过文件权限控制访问。

(一系列的接口。)

image-20220609164135630

文件系统缓存

主存(通常是DRAM)的一块区域用来缓存文件系统的内容,包含各种数据和元数据。

标准文件访问方式

image-20220609165648699


直接IO方式

image-20220609171148660

OPEN +O_DIRECT = 绕过内核缓冲区的直接访问,有效避免了CPU和内存的多余时间开销。要求内存边界对齐。

直接IO,绕过缓存,不会出现write成功数据丢失情况。

注意:直接IO的缺点就是如果访问的数据不在应用程序缓存中,那么每次数据都会直接从磁盘进行加载,这种直接加载会非常慢,通常直接IO跟异步IO结合使用会得到较好的性能。

示例:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define TOTAL 10

//直接IO要考虑到硬件特性
//磁盘最基本的单位是扇区,一个扇区512字节
#define BUF_LEN 512


int writeToFile(int fd,const char* buf,int len) {
    int wlen = 0;
    if ((wlen = write(fd, buf, len)) < 0) {
        fprintf(stderr,"write to %d failed,reason:%s.\n",fd,strerror(errno));
        return -3;
    }

    return wlen;
}

int main(int argc, char** argv) {

    //const char* TEXT = "This is a test.\n";

    char* buf = NULL;

    //buf = (char*)malloc(BUF_LEN); 
    //地址要是512的倍数——内存边界对齐

    posix_memalign((void**)&buf,512,BUF_LEN);
    strcpy(buf,"This is test.\n");

    const char* filename = "./io_test.txt";
    int fd = 0;
    int i = 0;

    fd = open(filename,O_RDWR | O_TRUNC | O_CREAT | O_DIRECT);
    if (fd < 0) {
        fprintf(stderr, "fopen %s failed,reason:%s.\n exit\n",filename,strerror(errno));
        return -1;
    }

    for (i = 0; i < TOTAL; i++) {
        if (writeToFile(fd, buf, BUF_LEN) < 0) {
            fprintf(stderr,"write to %s failed,reason: %s.\n exit\n",filename,strerror(errno));
            //return -2;
        }
        printf("%d\n",i+1);
    }

    printf("finished.\n");

    //printf("Start to sleep 30 second....\n");

    if (buf)free(buf);
    close(fd);
    return 0;
    
}

直接IO和标准方式进行对比

示例:测试20s内对同一文件的读取次数0

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define BUF_SIZE 512


int main(int argc, char** argv) {

    char* buf = NULL;
    const char* filename = "./open_compare.txt";
    int fd = -1;
    time_t start;
    time_t cur;
    int rlen = 0;
    int ret = 0;
    static int read_total = 0;


    ret = posix_memalign((void**)&buf,512,BUF_SIZE);
    if (ret)fprintf(stderr,"posix_memalign failed.reason:%s\n",strerror(errno));
    
    start = time(NULL);
    
    do 
    {
        read_total++;
        //fd = open(filename, O_RDWR | O_DIRECT);
        fd = open(filename,O_RDWR);
    
        if (fd < 0) { 
            fprintf(stderr, "fopen %s failed,reason:%s.\n exit\n", filename, strerror(errno));
            return -1;
        }


        do 
        {
            if ((rlen = read(fd, buf, BUF_SIZE)) < 0) {
                fprintf(stderr, "read to %s failed,reason: %s.\n exit\n", filename, strerror(errno));
            }
    
        } while (rlen>0);
        close(fd);
    
        cur = time(NULL);
    } while ((cur-start) < 20);
    
    printf("total time:%d\n",read_total);
    
    return 0;

}

直接IO

image-20220609235253805

标准方式

(高速页缓存,多次读取速度快。)

image-20220609235437775


O_SYNC

image-20220609233550525

缓存同步

为了保证磁盘系统与缓冲区内容一致,Linux系统提供了sync,fsync,fdatasync三个函数。

函数描述:向打开的文件写数据,成功返回写入的字节数,出错则返回-1。

#include<unistd.h>

int fsync(int fd);
int fdatasync(int fd);
void sync(void);

说明:

  • sync——将所有修改过的块缓冲区排入写队列,然后就返回,它并不等待实际写磁盘操作结束。
  • fsync——将fd对应文件的块缓冲区立即写入磁盘,并等待实际写磁盘操作结束返回。
  • fdatasync——类似fsync,但只影响文件的数据部分。而除数据外,fsync还会同步更新文件属性。

Linux文件IO流程图

image-20220610101719690

内核中会有一个线程,不断地将高速页缓冲区中的数据写入到物理磁盘中。

相关文章
|
1月前
|
Linux 数据安全/隐私保护 Windows
命令方式:window向linux传文件
【10月更文挑战第6天】本文介绍了如何在Linux系统中通过命令`ip a`获取IP地址,并在Windows系统下使用CMD命令行工具和SCP命令实现文件传输。示例展示了如何将D盘中的`mm.jar`文件上传至IP地址为192.168.163.122的Linux系统的/up/目录下,最后在Linux系统中确认文件传输结果。
234 65
|
24天前
|
运维 安全 Linux
Linux中传输文件文件夹的10个scp命令
【10月更文挑战第18天】本文详细介绍了10种利用scp命令在Linux系统中进行文件传输的方法,涵盖基础文件传输、使用密钥认证、复制整个目录、从远程主机复制文件、同时传输多个文件和目录、保持文件权限、跨多台远程主机传输、指定端口及显示传输进度等场景,旨在帮助用户在不同情况下高效安全地完成文件传输任务。
171 5
|
24天前
|
Linux Shell 数据库
Linux文件查找新姿势:总有一种你没见过
【10月更文挑战第18天】文件查找是Linux用户提升工作效率的重要技能。本文介绍了几种实用的文件查找方法,包括基础的`find`命令、快速的`locate`和`mlocate`、高效的`fd`工具、以及结合`grep`和`rg`进行内容搜索。此外,还提供了编写Shell脚本和使用图形界面工具的建议,帮助你更灵活地管理文件。
62 3
|
1月前
|
Linux Shell
Linux系统文件默认权限
Linux系统文件默认权限
|
6天前
|
Linux 开发工具 Perl
在Linux中,有一个文件,如何删除包含“www“字样的字符?
在Linux中,如果你想删除一个文件中包含特定字样(如“www”)的所有字符或行,你可以使用多种文本处理工具来实现。以下是一些常见的方法:
30 5
|
6天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
23 6
|
6天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
30 6
|
7天前
|
监控 Linux Perl
Linux 命令小技巧:显示文件指定行的内容
在 Linux 系统中,处理文本文件是一项常见任务。本文介绍了如何使用 head、tail、sed 和 awk 等命令快速显示文件中的指定行内容,帮助你高效处理文本文件。通过实际应用场景和案例分析,展示了这些命令在代码审查、日志分析和文本处理中的具体用途。同时,还提供了注意事项和技巧,帮助你更好地掌握这些命令。
21 4
|
13天前
|
网络协议 Linux
linux系统重要文件目录
本文介绍了Linux系统中的重要目录及其历史背景,包括根目录、/usr、/etc、/var/log和/proc等目录的结构和功能。其中,/etc目录下包含了许多关键配置文件,如网卡配置、DNS解析、主机名设置等。文章还详细解释了各目录和文件的作用,帮助读者更好地理解和管理Linux系统。
35 2
|
12天前
|
缓存 监控 Linux