Linux 应用开发基础02-文件 IO

文件 IO

在 Linux 系统中,一切都是“文件” :普通文件、 驱动程序、网络通信等等。 所有的操作,都是通过“文件 IO”来操作的。所以,很有必要掌握文件操作的常用接口。

1. 文件从哪来?

flowchart LR
    1[文件从哪来?] --> 2[磁盘/Flash/SD卡/U盘]
    1 --> 3[Linux内核提供的虚拟文件系统]
    1 --> 4[特殊文件 /dev/xxx 设备节点/ FIFD / Socket]

1.1 针对设备上存储的文件

这些文件以某种格式保存在某个设备上,要先 mount,以 SD卡挂载为例“

  1. sd 卡接入后,串口打印设备计入信息,为mmcblk0 P1 分区
[20351.183942] mmc0: host does not support reading read-only switch, assuming write-enable
[20351.206152] mmc0: new high speed SDHC card at address 5048
[20351.233934] mmcblk0: mmc0:5048 SD32G 29.7 GiB 
[20351.243628]  mmcblk0: p1
  1. 确认具体接入设备,并挂载设备
ls /dev
mount /dev/mmcblk0p1 /media
  1. 查看设备挂载情况,发现设备已挂载在最后
[root@imx6ull:~]# cat /proc/mounts 
/dev/root / ext4 rw,relatime,data=ordered 0 0
devtmpfs /dev devtmpfs rw,relatime,size=86120k,nr_inodes=21530,mode=755 0 0
proc /proc proc rw,relatime 0 0
devpts /dev/pts devpts rw,relatime,gid=5,mode=620,ptmxmode=666 0 0
tmpfs /dev/shm tmpfs rw,relatime,mode=777 0 0
tmpfs /tmp tmpfs rw,relatime 0 0
tmpfs /run tmpfs rw,nosuid,nodev,relatime,mode=755 0 0
sysfs /sys sysfs rw,relatime 0 0
debugfs /sys/kernel/debug debugfs rw,relatime 0 0
/dev/mmcblk0p1 /media vfat rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro 0 0

1.2 针对内核提供的虚拟文件系统

查看内核系统,其自动挂载。如何自动挂载要掌握根文件系统知识。

cat /proc/mounts
sysfs /sys sysfs rw,relatime 0 0

ls /sys
block     bus       class     dev       devices   firmware  fs        fsl_otp   kernel    module    power

也可以同样使用挂载命令 mount -t sysfs none /mnt

1,3 针对特殊文件-设备节点


哪个驱动由主设备号确定
哪个硬件由次设备号确定

2. 怎么访问文件?

2.1 通用的 IO 模型:open/read/write/lseek/close

涉及知识点

  1. man 命令查询相关函数帮助,确定引入的头文件
  2. int main(int argc, char** argv) 变长参数
  3. open/read/write/lseek/close 使用
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

/*
Usage: ./copy 1.txt 1copy.txt
    argc = 3
    argv[1] = "./copy"
    argv[2] = "1.txt"
    argv[3] = "1copy.txt"
*/
int main(int argc, char** argv){
    int fd_old, fd_new;
    int buf[1024];
    int count =10 ;

    if(argc != 3)
    {
        printf("Usage: ./copy 1.txt 1copy.txt\n");
        return -1;
    }
    
    //1. open "srcfile" file
    fd_old = open(argv[1],O_RDONLY,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
    if(fd_old == -1){
        printf("%s open failed\n",argv[1]);
        return -1;
    }

    //2. create "dstfile" file
    /*creat()
       A call to creat() is equivalent to calling open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.*/
    fd_new = open(argv[2],O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
    if(fd_new == -1){
        printf("%s open failed\n",argv[2]);
        return -1;
    }

    //3. copy file from "srcfile" to "dstfile"
    /*
        read() when fewer bytes are actually available,Bytes read from fd are lesser than the number of bytes requested (1024 bytes) 
        write() On success, the number of bytes written is returned. when the number of bytes are not euqal with specified value, some write error occurs.
    */
    while((count = read(fd_old, buf, 1024))>0){
        if(write(fd_new, buf, count)!=count)
        {
            printf("cannot write %s\n",argv[1]);
            return -1;
        }
    }

    //4. close file
    close(fd_new);
    close(fd_new); 
    return 0;
}

2.2 不是通用的函数:ioctl/mmap

在 Linux 中,还可以把一个文件的所有内容映射到内存,然后直接读写内存即可读写文件。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>

/*
Usage: ./copy 1.txt 1copy.txt
    argc = 3
    argv[1] = "./copy"
    argv[2] = "1.txt"
    argv[3] = "1copy.txt"
*/
int main(int argc, char** argv){
    int fd_old, fd_new;
    struct stat srcfilestat;
    char* buf;

    if(argc != 3)
    {
        printf("Usage: ./copy 1.txt 1copy.txt\n");
        return -1;
    }
    
    //1. open "srcfile" file
    fd_old = open(argv[1],O_RDONLY,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
    if(fd_old == -1){
        printf("%s open failed\n",argv[1]);
        return -1;
    }

    //2. Determing the size of old file
    if(fstat(fd_old,&srcfilestat)==-1){
        printf("fsta(%s) failed\n",argv[1]);
        return -1;
    }

    // 3. mmap file
    buf = mmap(NULL, srcfilestat.st_size, PROT_READ, MAP_SHARED, fd_old,0);
    if(buf == MAP_FAILED){
        printf("can not mmap file %s\n", argv[1]);              
        return -1;
    }

    //4. create "dstfile" file
    /*creat()
       A call to creat() is equivalent to calling open() with flags equal to O_CREAT|O_WRONLY|O_TRUNC.*/
    fd_new = open(argv[2],O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
    if(fd_new == -1){
        printf("%s open failed\n",argv[2]);
        return -1;
    }

    //5. copy file from "srcfile" to "dstfile"
    /*
        read() when fewer bytes are actually available,Bytes read from fd are lesser than the number of bytes requested (1024 bytes) 
        write() On success, the number of bytes written is returned. when the number of bytes are not euqal with specified value, some write error occurs.
    */
    if(write(fd_new, buf, srcfilestat.st_size)!=srcfilestat.st_size)
    {
        printf("cannot write %s\n",argv[1]);
        return -1;
    }

    //4. close file
    close(fd_new);
    close(fd_new); 
    return 0;
}

3. 系统调用函数怎么进入内核?

4. 内核的 sys_open、sys_read 会做什么?

文件 IO.drawio
文件 IO.drawio

posted @ 2022-07-26 17:45  Oddpage  阅读(58)  评论(0编辑  收藏  举报