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\n",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\n");
    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。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM