文件讀寫
【文件描述符】
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 }
結果:得到了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 }
結果:
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。