zoukankan      html  css  js  c++  java
  • Linux 文件读写操作与磁盘挂载

    文件读写


    文件描述符

           Linux下,通常通过open打开一个文件,它然后返回给我们一个整数,通过这个整数便可以操作文件,这个整数我们称文件描述符(fd)。对应被打开的文件,它也是一种系统资源,那么fd打的能打开多少个文件呢?可以通过这两个命令查看

            ulimit –n        //查看系统打开文件的数据

           ulimit –n  数值    //将打开文件修改为数值大小。

    系统到底能打开多少文件由什么决定?

          是一个叫file-max的配置文件决定的。可以通过 cat  / proc/sys/fs/file_amx  查看文件打开数目的最大值 (1G大小相当于可打开10万个文件)

    【open函数】

    文件打开函数open有两种

    头文件 #include <fcntl.h>
    int
    open(const char* pathname , //打开文件名 int flag) O_RDONLY //只读 O_WRONLY //只写 O_RDWR //读写 O_CREAT //打开的同时创建(如果文件存在就不创建) O_TRUNC //打开时清除文件内容
             O_EXCL //若O_CRETE和O_EXCL被设置且文件存在,open调用失败
             O_NDELAY //延迟读写标记
    int open(const char* pathname, //文件路径 int flags, // 与前面相同 mode_t mode); //文件存取权限标志 如 666;

    注意:参数flag必须在O_RDONLY,O_WRONLY,O_RDWR中有且只能选取一个,然后用"|"符合于其他标准组合(相当于或起来)。函数调用成功时返回打开的文件描述符,失败返回-1.
    文件描述符分配规则:从小到大找到第一个没有被分配使用的文件描述符。
    查看该进程文件描述符: /proc/pid/fd (pid 当前进程标识符)

    【系统IO:read  write】

    //ssize_t int  =  size_t unsigned int
    size_t write(int fd ,
            const void* buf,   //想写入的数据位置
            size_t len)         //要写入数据大小

    返回实际写入的字节数,在合适的时机将数据从内核区写入磁盘
    ssize_t read(int fd,    //open打开的文件描述符
            void* buf,      //用户准备的缓存区
            size_t count)   //缓存区大小

    返回读取的字节数,(如果返回值为0,表示读取结束),顺序读写文件

     read/write函数调用不仅可以用于普通文件,还适用于管道、流设备和设备文件。多个程序同时读写一份文件,会产生竞争问题,若希望按预定次序进行读写,则应使用文件锁。

    2. 定位文件的当前读写位置:off_t lseek(int fd, off_t offset, int whence)

    off_t lseek(int fd,
            off_t offset,    //偏移量
            int whence)      //基准位置   有如下3个基准:
                              SEEK_SET
                              SEEK_CUR
                             SEEK_END
    函数返回值:新定位的读写位置,失败返回-1.

    作用:可以通过它来求得文件大小

    先写入一个文件:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<unistd.h>
     5 #include <sys/stat.h>
     6 #include <fcntl.h>  
     7 
     8 
     9 void main()  
    10 {  
    11     int file_size = 1024*1024;  
    12     int fd=open("test.txt", O_RDWR);  
    13     if(fd < 0)  
    14     {   
    15         perror("open test.txt");  
    16         exit(-1);  
    17     }   
    18     lseek(fd, file_size-1, SEEK_END);  
    19     write(fd,"0", 1); 
    20     close(fd);
    21 
    22 }
    lseek创建一文件

    结果:得到了1M字节的.txt文件

    tp@tp:~/Linux/day3$ vim test.txt 
    tp@tp:~/Linux/day3$ ls -lh
    total 24K
    -rw-rw-r-- 1 tp tp  479 Apr 13 22:38 1.cpp
    -rw-rw-r-- 1 tp tp  100 Apr 13 22:38 abc.txt
    -rwxrwxr-x 1 tp tp 8.7K Apr 13 23:22 a.out
    -rw-rw-r-- 1 tp tp  414 Apr 13 23:25 lseek.c
    -rw-rw-r-- 1 tp tp    0 Apr 13 23:26 test.txt
    tp@tp:~/Linux/day3$ gcc lseek.c 
    tp@tp:~/Linux/day3$ ./a.out
    tp@tp:~/Linux/day3$ ls -lh
    total 28K
    -rw-rw-r-- 1 tp tp  479 Apr 13 22:38 1.cpp
    -rw-rw-r-- 1 tp tp  100 Apr 13 22:38 abc.txt
    -rwxrwxr-x 1 tp tp 8.7K Apr 13 23:26 a.out
    -rw-rw-r-- 1 tp tp  414 Apr 13 23:25 lseek.c
    -rw-rw-r-- 1 tp tp 1.0M Apr 13 23:26 test.txt

    利用lseek求文件大小

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 #include<sys/types.h>
     4 #include<unistd.h>
     5 #include <sys/stat.h>
     6 #include <fcntl.h>  
     7 
     8 
     9 void main()  
    10 {  
    11     int fd=open("test.txt", O_RDWR);  
    12     if(fd < 0)  
    13     {   
    14         perror("open test.txt");  
    15         exit(-1);  
    16     }   
    17     printf("file size:%ld
    ",lseek(fd, 0, SEEK_END));
    18     close(fd);
    19 
    20 }
    利用lseek获取文件大小

    结果:

    tp@tp:~/Linux/day3$ gcc lseek.c 
    tp@tp:~/Linux/day3$ ./a.out
    file size:1048576
    tp@tp:~/Linux/day3$ du -h test.txt 
    4.0K    test.txt

    注意:①ls –l 查看文件字符数  ②du –h 查看实际占用的物理磁盘块数

    来看看test.txt里面的内容:

             

    od 命令来查看文件中不能直接显示在终端的字符:

    tp@tp:~/Linux/day3$ od -s test.txt 
    0000000      0      0      0      0      0      0      0      0
    *
    3777760      0      0      0      0      0      0      0  12288
    4000000

     注意到 有一个“*”存在,这其实就是空洞文件,它指没有被实际写入文件的所有字节。这些字节由重复的 0 表示。(据百度百科还是由于offset > 实际文件大小所致)

    同时,因为ls展现的是文件的逻辑大小,即在文件系统表现出来的大小,而du展现的是文件物理大小,也就是文件在磁盘上实际所占的block数;所以说,空洞文件在文件系统表现的还是和普通文件一样的,但是实际上文件系统并没有给他分配所表现出来的那么多空间,只是存放了有用的信息。

    【dup命令】

    原型   #include <unistd.h>
         int dup(int oldfd);
         int dup2(int oldfd, int newfd);

    说明:

      dup用来复制oldfd所指的文件描述符。但返回的是最小且当前尚未被使用的文件描述符,若有错误则返回-1,错误代码存入errno中。返回的新文件描述符就会和oldfd指向同一个文件,共享所有的锁定,读写指针,和各项权限或标志位。
        dup2可以用参数newfd指定新文件描述符的数值。若newfd已经被程序使用,系统就会将其关闭以释放该文件描述符;若newfd与oldfd相等,dup2将返回newfd,而不关闭它。dup2调用成功返回新的文件描述符,出错则返回-1。

    文件描述符在PCB里面一张文件描述符表存着,且0,1,2 代表标准输入,标准输出,标准出错。

    应用:结合前面的文件操作函数,可以实现“输出重定向”

    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/types.h>
    #include<unistd.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    
    int main(void)
    {
        int fd; 
        if((fd = open("test1.txt", O_RDWR|O_CREAT))== -1) 
        {   
            perror("open error");
            exit(1);
        }   
        close(1);  //关闭标准输出
        dup(fd);   //复制fd文件描述符返回到当前最小可用文件描述1(标准输出)
                   //此时 1和fd指向同一个文件表(如上图)
    //  dup2(fd, 1);  //和dup类似,不过它可以直接为oldfd指定成为newfd文件描述符数值
        close(fd);   //关闭oldfd 
        printf("gggggg
    ");
        return 0;
    }
    结果:
      

    磁盘


    磁盘分类:

       ①IDE接口类型  如hda,hdb,hdc. 等。 hda一般指第一块硬盘,IDE类型安装更方便

       ②SCSI (SARA)接口类型    linux下通常是此种类型的接口硬盘,如sda。 linux下,u盘、硬盘通常被识别为此种类型。

    区别:

               U盘和SARA硬盘的在Linux上面的文件名一般是 /dev/sd[a-p]。与IDE接口不同的是,SCSI/USB接口的磁盘没有固定的顺序,一般根据Linux内核检测到磁盘的顺序检测。

    相关命令:

       lsblk [选项] [设备]    // 查看分区使用情况

       df [选项] [查看文件名]  //查看磁盘使用情况

    自己挂载一块硬盘

                

    步骤:


    1. 进入虚拟机设置 按引导创建一块新硬盘,如

        

      然后重启虚拟机。

    2. 分区  使用fdisk /dev/sdb

       此时 lsblk ,查看到多了一个1G的硬盘(disk)

        

       然后 fdisk  /dev/sdb  

    tp@Bit:~$ sudo fdisk /dev/sdb
    [sudo] password for tp: 
    
    Welcome to fdisk (util-linux 2.30.1).
    Changes will remain in memory only, until you dec
    Be careful before using the write command.
    
    Device does not contain a recognized partition ta
    Created a new DOS disklabel with disk identifier 
    
    Command (m for help): m

      输入m 可以查看帮助,n:代表新创建分区,p:列出分区表,w:把分区表写入硬盘并退出

    Command (m for help): n
    Partition type
       p   primary (0 primary, 0 extended, 4 free)
       e   extended (container for logical partitions)
    Select (default p): p
    Partition number (1-4, default 1): 1
    First sector (2048-2097151, default 2048): 
    Last sector, +sectors or +size{K,M,G,T,P} (2048-2097151, default 2097151): 
    
    Created a new partition 1 of type 'Linux' and of size 1023 MiB.
    
    Command (m for help): w   
    The partition table has been altered.
    Calling ioctl() to re-read partition table.
    Syncing disks.

    3. 格式化磁盘   mkfs  -t  ext4 /dev/sdb1

      此时,lsblk 一下 sdb下面就已创建了分区

    tp@Bit:~$ lsblk
    NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
    sda      8:0    0   20G  0 disk 
    └─sda1   8:1    0   20G  0 part /
    sdb      8:16   0    1G  0 disk 
    └─sdb1   8:17   0 1023M  0 part 
    sr0     11:0    1  1.4G  0 rom  
    tp@Bit:~$ sudo mkfs -t ext4 /dev/sdb1
    mke2fs 1.43.5 (04-Aug-2017)
    /dev/sdb1 contains a ext4 file system
        created on Fri Apr 13 18:11:13 2018
    Proceed anyway? (y,N) y
    Creating filesystem with 261888 4k blocks and 65536 inodes
    Filesystem UUID: fe547447-dd2e-423e-bd17-af8078c09fb5
    Superblock backups stored on blocks: 
        32768, 98304, 163840, 229376
    
    Allocating group tables: done                            
    Writing inode tables: done                            
    Creating journal (4096 blocks): done
    Writing superblocks and filesystem accounting information: done

    4. 挂载  mount  [挂载目录] [被挂载目录]   (重启后挂载的硬盘会消失)

      

      此时,myDisk目录下出现lost+found 目录。 挂载成功。

    5. 自动挂载   /etc/fstab        

      以上面的挂载方式,就可以为U盘,新插硬盘进行挂载了,但是当重启虚拟机以后,我们挂载的目录可能就找不到了,因为它没有添加到配置文件里面,所以不能像 / 目录那样自动挂载。如要自动挂载的话,就还得为相应配置文件添加内容。

     先打开配置文件  /etc/fstab ,然后添加 :

    /dev/sdb1    /myDisk   ext4     defaults    0  0

    各选项分别是:1.挂载目录
           2.被挂载点
           3.文件系统类型
           4.挂载选项
           5.设置是否使用dump备份,置0为不备份,置1,2为备份,但2的备份重要性比1小
           6.设置是否开机的时候使用fsck检验所挂载的磁盘,置0为不检验,置1,2为检验,但置2盘比置1的盘晚检验。

      

      df -h 一下

      

      ok! 挂载完成。

    6. 卸载    umount  [挂载目录] [被挂载目录]

      没配置,直接umount就可以了;配置了配置文件,将配置文件改回,再umount。 

  • 相关阅读:
    LWIP的底层结构(物理层)
    Source insight 支持汇编
    Camera Vision
    i2c-tools的使用方法及举例
    浅析C语言中strtol()函数与strtoul()函数的用法
    CF540C Ice Cave
    CF540B School Marks
    hdu5122 K.Bro Sorting
    hdu1013 Digital Roots
    蓝桥杯 算法提高 递推求值
  • 原文地址:https://www.cnblogs.com/tp-16b/p/8810613.html
Copyright © 2011-2022 走看看