linux 文件系統

linux的文件系統是一個廣義的文件系統,能夠認爲linux系統對任何設備和對象的操做都是等價於對文件的操做。linux

linux系統對全部可操做對象進行了高度的抽象,將其概括爲這麼幾類:網絡

  1. 普通文件:就是狹義概念上的存儲在磁盤中的文件,是純粹的存儲數據的文件,例如文本文件,圖片文件,可執行文件等;數據結構

  2. 字符設備文件:一般指輸入輸出終端,鍵盤,串口等,一般能夠用操做文件的方式來操做字符設備文件,由於對這類設備的讀寫實際上是讀寫的字符流;架構

  3. 塊設備文件:有硬盤,軟盤和RAM等,塊設備文件一般公國內存緩衝區讀寫數據,支持塊數據讀取和隨機讀取,讀寫性能更好;app

  4. socket文件:網絡通訊的文件描述符,支持像操做普通文件同樣操做網絡數據的讀寫;異步

linux提供了虛擬文件系統架構,要求全部設備都提供一致的文件操做接口,方便用戶像操做文件同樣操做全部設備,所以能夠說linux系統下,一切操做的都是文件。socket

 

文件描述符函數

文件描述符是對一個操做文件的抽象標識,它被用戶空間和內核空間的樞紐共同使用。當用戶空間對一個文件描述符進行操做時,例如對一個文件描述符進行操做時,當內核進行系統調用時,將根據該文件描述符找到對應的真實設備進行操做,並將結果返回用戶空間。性能

文件描述符一般是一個整數標識,所以它根據系統不一樣,有一個上線值(一般是0-OPNE_MAX)。因此,咱們在使用完一個文件後,應該儘快釋放它(一般調用close函數)。ui

1. 打開文件和建立文件

頭文件:sys/types.h sys/stat.h fcntl.h

int open(const char* filepath, int flags);

int create(const char* filepath, int flags, mode_t mode);

打開和建立成功返回一個文件描述符,失敗返回-1。一般filepath的字符長度也會有限制,若是超出長度會被截斷。

flags的選項:

  O_RDONLY (0 只讀)

  O_WRONLY (1 只寫)

  O_RDWR (2 讀寫)  

  O_APPEND (寫操做追加到末尾)

  O_CREATE (若是文件不存在,建立一個,須要mode來設置權限)

  O_EXCL (查看文件是否存在。若是同時指定O_CREATE,而且文件已經存在,會返回錯誤)

  O_TRUNC (將文件長度截斷爲0)

mode的選項:

  S_IRWXU 用戶有讀寫和執行權限

  S_IRUSR 用戶有讀權限

  S_IWUSR 用戶有寫權限

  S_IXUSR 用戶有執行權限

  S_IRWXG 組用戶有讀寫和執行的權限

  S_IRGRP 組用戶有讀權限

  S_IWGRP 組用戶有寫權限

  S_IXGRP 組用戶有執行權限

  S_IRWXO 其餘用戶有讀寫和執行權限

  S_IROTH 其餘用戶有讀權限

  S_IWOTH 其餘用戶有寫權限

  S_IXOTH 其餘用戶有執行權限

對文件的操做默認都是阻塞的,即必須等到文件操做返回才能繼續。

2. 關閉文件

int close(int fd);

若是成功返回0,失敗返回-1。在關閉文件後,系統能夠再次使用該文件描述符,若是使用後不關閉,進程也會在退出時關閉全部打開的文件描述符,可是可能形成文件描述符不夠用的狀況,致使沒法再打開新的文件。

3. 讀取文件

頭文件:unistd.h

ssize_t read(int fd, void* buf, size_t count);

從文件fd讀取count字節的字節流並存到buf指向的內存地址中。讀取成功返回讀取成功的字節數,若是返回0標識讀取到文件末尾,讀取失敗返回-1。ssize_t的定義是依賴平臺,多是long或者int。實際狀況返回的字節數可能小於count指定的大小,表示沒法讀取到count大小的字節,已經將文件中當前剩餘的全部字節所有讀取出來。

4. 寫文件

頭文件:unistd.h

ssize_t write(int fd, const void* buf, size_t count);

向文件fd中寫入指定count大小的數據,數據來自buf指向的內存地中的字節流。若是成功返回寫入成功的字節數,失敗返回-1。

5. 文件偏移

頭文件:sys/types.h unistd.h

off_t lseek(int fd, off_t offset, int whence);

文件偏移量:文件操做的當前位置,全部文件操做都是從文件偏移量開始的。若是在打開文件的時候,指定了O_APPEND,文件偏移量就是文件的長度,即末尾處,不然偏移量爲0,即文件起始位置。

lseek函數能夠更新文件fd的偏移量,offset可爲整數或負數,表示相對whence的偏移大小。

whence選項:

  SEEK_SET:文件的開始位置;

  SEEK_CUR:文件的當前位置;

  SEEK_END:文件的結尾位置;  

若是函數執行成功返回偏移量的值,可能爲負數,失敗返回-1。

當向文件寫數據時,若是使用lseek設置偏移量超出了文件大小,當繼續向文件寫入數據時,中間的空白字節會用'\0'填充。

6. 獲取文件狀態

頭文件 sys/types.h sys/stat.h unistd.h

int stat(const char* path, struct stat* buf);

int fstat(int fd, struct stat* buf);

int lstat(const char* path, struct stat* buf);

若是獲取成功返回0,失敗返回-1。文件狀態的數據寫入buf指向的數據結構中。

7. 文件空間映射

頭文件:sys/mman.h

void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);

該函數將文件映射到內存中,而後就能夠採用內存操做,沒必要再使用read和write函數,性能更好。

start:內存的開始地址,可是一般不須要指定,設置爲NULL,表示由系統決定映射的地址,在返回值中體現;

length:表示映射的地址長度,即從文件映射到內存中的數據大小;

prot:映射區域的保護方式,能夠由多個值進行組合;

  PROT_EXEC 可執行區域

  PROT_READ 可讀取區域

  PROT_WRITE 可寫區域

flags:設定映射區域的類型,選項和對映射區域是否能夠操做,能夠由多個值進行組合;

  MAP_FIXED 若是參數start指定的地址沒法創建映射,映射會失敗,一般不指定該值,將start設置爲NULL,由系統選定映射地址;

  MAP_SHARED:映射區域是多進程共享的,對映射區域的操做都會影響原來的文件;

  MAP_PRIVATE:映射區域的寫操做都會產生一個副本,而且寫操做不會影響原來的文件;

  MAP_DENYWRITE:對文件的寫入操做被禁止,只能經過對映射區域的操做來實現對文件的操做;

  MAP_LOCKED:將映射區域鎖定,不會被虛擬內存重置;

int munmap(void* start, size_t length);

取消文件映射,一般在映射區域操做完成後調用,而後關閉文件;

 

 1 int fd = open("leo.txt", O_RDWR | O_CREAT, S_IRWXU);
 2         if (fd == -1) {
 3                 printf("create file failed.");
 4         }
 5         else {
 6                 char buf[] = "leo is me!";
 7                 write(fd, buf, strlen(buf));
 8 
 9                 char* ptr = (char*)mmap(NULL, strlen(buf), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
10                 if ((char*)-1 == ptr) {
11                         printf("mmap failed.");
12                 }
13                 else {
14                         memcpy(ptr, "123", 3);
15                         munmap(ptr, strlen(buf));
16                         close(fd);
17                 }
18         }

 

8. 文件屬性操做

頭文件:unistd.h fcntl.h

int fcntl(int fd, int cmd);

int fcntl(int fd, int cmd, long arg);

int fcntl(int fd, int cmd, struct flock* lock);

對文件的屬性進行修改,失敗返回-1。

fcntl的功能:

  複製文件描述符:cmd = F_DUPFD,返回值是新的文件描述符。新的文件描述符是大於或等於第三個參數的還沒有使用的文件描述符中的最小值;

  獲取或設置文件描述符:cmd = F_GETFD/F_SETFD;

  獲取或設置文件狀態值:cmd = F_GETFL/F_SETFL;

    文件狀態值:

    O_RDONLY 只讀

    O_WRONLY 只寫

    O_RDWR 讀寫

    O_APPEND 將寫入添加到末尾

    O_NONBLOCK 非阻塞方式

    O_SYNC 異步方式

    O_ASYNC 同步方式

    正確得到O_RDONLY,O_WRONLY和O_RDWR標誌位的方法是和O_ACCMODE進行與操做才能得到;

int fd = open("leo.txt", O_RDWR | O_CREAT, S_IRWXU);
if (fd == -1) {
  printf("create file failed.");
}
else {
  int flags = fcntl(fd, F_GETFL, 0);
  if (flags < 0) {
    printf("get flags failed123333.");
  }
  else {
    int accmode = flags & O_ACCMODE;
    if (accmode == O_RDONLY) {
      printf("file only read. \n");
    }
    else if (accmode == O_WRONLY) {
      printf("file only write \n");
    }
    else if (accmode == O_RDWR) {
      printf("file can be read and write. \n");
  }
  else
  {
    printf("accmode invalid. \n");
  }

 
 

  flags |= O_APPEND;
  int result = fcntl(fd, F_SETFL, &flags);
  if (result < 0) {
    printf("set file flag failed. \n");
  }

 
 

  int newflags = fcntl(fd, F_GETFL, 0);
  if (newflags & O_APPEND) {
    printf("file append. \n");
  }
  if (newflags & O_NONBLOCK) {
    printf("file non block. \n");
  }

 
 

    close(fd);
  }
}

  獲取或設置文件信號的發送對象:cmd = F_GETTOWN/F_SETTOWN/F_GETSIG/F_SETSIG;

int uid = fcntl(fd, F_GETOWN); // 獲取接受信號SIGIO和SIGURG的進程id
int uid = fcntl(fd, F_SETOWN, 10000); // 將接受信號SIGIO和SIGURG的進程設置爲id爲10000的進程

  獲取或設置記錄鎖:cmd = F_GETLK/F_SETLK/F_SETLKW;

  獲取或設置文件租約:cmd = F_GETLEASE/F_SETLEASE;

9. 文件輸入輸出控制

頭文件:sys/iotl.h

int ioctl(int device, int request, ...);

經過向設備發送命令來控制設備,失敗返回-1。device爲一個打開的設備號,其餘參數根據設備驅動程序來決定。

 

#include "stdlib.h"
#include "stdio.h"
#include <unistd.h>
#include <fcntl.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>

int main(void)
{int fd = open("/dev/cdrom", O_RDONLY | O_NONBLOCK);
    if (fd > 0) {
        if (!ioctl(fd, CDROMEJECT, NULL)) {
            printf("ok \n");
        }
        else {
            printf("fail \n");
        }
    }

    getchar();

    return 0;
}
相關文章
相關標籤/搜索