<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                > Linux 系統中,外存中的數據都是以文件的形式保存的,對目錄和各種設備的操作也等同于文件的操作。 [TOC] ## 1 Linux 系統文件和文件系統 ### 1.1 Linux 文件類型(ls -l) > 表1.1.1 - 各種文件類型含義 文件類型 | 標識 ---- | ---- 普通文件 | 第 1 個字符為 `-` 目錄文件 | 第 1 個字符為 `d` 硬鏈接文件 | 除了顯示的文件數量,其他都和某個普通文件一模一樣的文件 軟鏈接文件 | 第 1 個字符為 `l` 塊設備文件 | 第 1 個字符為 `b` socket | 第 1 個字符為 `s` 字符設備文件 | 第 1 個字符為 `c` 管道文件 | 第 1 個字符為 `p` setUid 可執行文件 | 第 4 個字符為 `s` setGid 可執行文件 | 第 7 個字符為 `s` setUid 加 setGid 文件 | 第 4 個和第 7 個字符都是 `l` > 清單1.1.2 - C 語言獲取 Linux 文件類型示例 ```c #inclue <stdlib.h> // 執行成功則返回 shell 命令的值; // 調用/bin/sh 失敗返回127; // 其他失敗原因返回-1; // 參數string為NULLL,則返回非零值 int res = system("ls -l"); ``` ### 1.2 Linux 文件權限(ls -l) > 清單1.2.1 將 `/etc/passwd` 文件設置為文件所有者可讀可寫,其他用戶為只讀權限 ```c #include <sys/types.h> #include <sys/stat.h> // 權限更改成功返回0; // 失敗返回-1; // 錯誤原因存于errno chmod("/etc/paddwd", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); ``` 權限參數(mode)的組成方式:`S_I` `R/W/X` `USR/GRP/OTH` 其中 USR=所有者,GRP=組,OTH=其他用戶;R=讀,W=寫,X=執行 ---- 通過設置權限掩碼(umask),可以設置系統文件在創建時的**初始權限** > 清單1.2.2 umask 函數示例 ```c #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> int main() { system("touch old_umask_file"); // 創建文件 mode_t new_umask = 0666; // 八進制的666 mode_t old_umask = umask(new_umask); // 設置系統權限掩碼為0666,返回系統原來的權限掩碼 system("touch 0666_umask_file"); // 設置過系統權限掩碼后,創建的文件 system("mkdir 0666_umask_dir"); // 設置過系統權限掩碼后,創建的文件夾 } /* ls-l d--x--x--x 2 zhaoxuyang03 zhaoxuyang03 4096 1月 8 22:50 0666_umask_dir ---------- 1 zhaoxuyang03 zhaoxuyang03 0 1月 8 22:52 0666_umask_file */ ``` ---- > 在 Linux 系統中,定義了 `stat` 結構來存放文件屬性 ```c struct stat { dev_t st_dev; // 文件所在設備的 ID ino_t st_ino; // 索引節點號 mode_t st_mode; // 文件保護模式 nlink_t st_nlink; // 文件的鏈接數(硬鏈接) uid_t st_uid; // 用戶 ID gid_t st_gid; // 組 ID dev_t st_rdev; // 設備號,針對設備文件 off_t st_size; // 文件字節數 unsigned long st_blksize; // 系統塊的大小 unsigned long st_blocks; // 文件所占塊數 time_t st_atime; // 最后一次訪問時間(access) time_t st_mtime; // 最后一次修改時間(modify) time_t st_ctime; // 最后一次改變時間(指屬性) }; ``` > 下例展示了如何獲取文件大小 ```c #include <unistd.h> #include <sys/stat.h> int main() { struct stat buf; stat("/etc/passwd", &buf); printf("%d\n", buf.st_size); return 0; } ``` ## 2 不帶緩存的文件 I/O 操作 (File) 不帶緩存的文件 I/O 操作,包括系統調用或 API 的 I/O 操作,是由操作系統提供的,符合 POSIX 標準,但是不能移植到非 POSIX 標準的操作系統(如 Windows)。主要用到以下操作: 函數 | 作用 ---- | ---- creat | 創建文件 open | 打開或創建文件 close | 關閉文件 read | 讀文件 write | 寫文件 lseek | 移動文件的讀寫位置 flock | 鎖定文件或解除鎖定(用于文件加建議鎖) fcntl | 文件描述符操作(用于文件加強制鎖) ### 2.1 文件的創建 (creat) creat 函數用于創建文件,成功則由內核返回一個最小可用的文件描述符,若有錯誤發生則會返回-1 ```c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int creat(const char* pathname, mode_t mode); ``` ### 2.2 文件的打開和關閉 (open & close) - open 函數用于打開一個存在或不存在的文件,成功則由內核返回一個最小可用的文件描述符,若有錯誤發生則會返回-1 - close 函數用于關閉一個打開的文件,成功關閉則返回0,發生錯誤時返回-1;當一個進程終止時,它所有已打開的文件都由內核自動關閉 ```c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open(const char* pathname, int flags); int open(const char* pathname, int flags, mode_t mode); int close(int fd); ``` flags 值 | 參數說明 ---- | ---- O_RDONLY | 以只讀模式打開 O_WRONLY | 以寫入模式打開 O_RDWR | 以讀寫模式打開 O_APPEND | 在文件尾寫入數據 O_TRUNC | **設置文件的長度為0**,并舍棄現存的數據 O_CREAT | 創建文件,可使用 mode 參數設置訪問權限 O_EXCL | 與 O_CREAT 一起使用,如果要創建的文件已存在,則打開失敗 ### 2.3 文件的讀寫操作 (write & read) - read 函數用于從指定的文件描述符中讀出數據 - 常規文件的讀寫不會阻塞,除非從網絡或控制臺等場景讀入 - write 函數用于向打開的文件寫入數據,寫操作從文件當前位置開始 - lseek 函數用于在指定的文件描述符中將文件指針定位到相應的位置 ```c #include <unistd.h> ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void* buf, size_t count); ``` ### 2.4 文件的非阻塞操作 (O_NONBLOCK) - 文件打開時用 flags 中的 O_NONBLOCK 來表示 write/read 是非阻塞的 - 非阻塞與阻塞的區別在于**沒有數據到達的時候是否立刻返回** - 如果設備暫時沒有數據可讀就返回-1,同時置 errno 為 `EWOULDBLOCK` - 非阻塞主要用在網絡服務中,使得服務器得到最大的利用 ```c 非阻塞時設置 flags |= O_NONBLOCK 阻塞時設置 flags &= ~O_NONBLOCK 非阻塞程序結構如下: while(1) { 非阻塞read(設備1); if(設備1有數據到達) { 處理數據; } 非阻塞read(設備2); if(設備2有數據到達) { 處理數據; } ...... } ``` ### 2.5 文件上鎖 (flock & fcntl) - flock 用于給文件加建議鎖,一般情況下,系統很少使用建議鎖 - fcntl 用于給文件加強制鎖,內核將阻止其他任何文件對其進行讀寫操作 - 通過 F_GETFL, F_SETFL 分別用于讀取、設置文件的屬性,能夠更改的文件標志有 O_APPEND, O_ASYNC, O_DIRECT, O_NOATIME, O_NONBLOCK ```c // 1. 獲取文件的 flags flags = fcntl(fd, F_GETFL, 0); // 2. 增加文件的某個 flgas,例如將阻塞設置為非阻塞 flags |= O_NONBLOCK; // 3. 設置文件的 flags fcntl(fd, F_SETFL, flags); ``` ---- ```c struct flock { short l_type; // 加鎖的類型:F_RDLCK, F_WRLCK, F_UNLCK short l_whence; // 對 l_start 的解釋,分別為 SEEK_SET, SEEK_CUR, SEEK_END off_t l_start; // 指明加鎖部分的開始位置 off_t l_len; // 加鎖的長度 pid_t l_pid; // 加鎖進程的進程id } ``` ```c #include <sys/file.h> /* operation有四種情況: - LOCK_SH:建立共享鎖定,多個進程可同時對同一個文件作共享鎖定 - LOCK_EX:建立互斥鎖定,一個文件同時只有一個互斥鎖定 - LOCK_UN:解除文件鎖定狀態 - LOCK_NB:無法建立鎖定時,此操作可不被阻斷,馬上返回進程,通常與 LOCK_SH 或 LOCK_EX 做 OR 組合 單一文件無法同時建立共享鎖定和互斥鎖定,而當使用dup()或fork()時文件描述詞不會繼承此種鎖定 */ int flock(int fd, int operation); 返回0表示成功,若有錯誤則返回-1,錯誤代碼存于errno ``` ```c #include <unistd.h> #include <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); 返回0表示成功,若有錯誤則返回-1,錯誤代碼存于errno ``` ## 3 帶緩存的流文件 I/O 操作 (InputStraem & OutputStream) 帶緩存的流文件 I/O 操作,又稱標準 I/O 操作,符合 ANSI C 標準,在內存中開辟緩沖區,為程序的每一個文件使用,比不帶緩存的文件 I/O 程序方便移植;主要用到以下操作: 函數 | 作用 ---- | ---- fopen | 打開或創建文件 fclose | 關閉文件 fgetc | 由文件中讀取一個字符 fputc | 將一指定字符寫入文件流中 fputs | 將一指定的字符串寫入文件流中 fread | 從文件流成塊讀取數據 fwrite | 將數據成塊寫入文件流 fseek | 移動文件流的讀寫位置 rewind | 重設文件流的讀寫位置到文件開頭 ftell | 取得文件流的讀取位置 ### 3.1 流文件的打開和關閉 (fopen & fclose) - fopen 函數用于打開文件 - fclose 函數用于關閉文件 ```c #include <stdio.h> FILE *fp; if ((fp=fopen("xxx", "a+")) == NULL) { exit(0); } fclose(fp); ``` ```c FILE* fopen(const char*path, const char* mode); - r 表示打開只讀文件。該文件必須存在 - r+ 表示打開可讀寫的文件。該文件必須存在 - w 表示打開只寫文件。若文件存在則文件長度清為零,即**該文件內容會清空**;若文件不存在則創建該文件 - w+ 表示打開可讀寫文件。若文件存在則文件長度清為零,即**該文件內容會清空**;若文件不存在則創建該文件 - a 表示以附加方式打開只寫文件。若文件不存在,則會建立該文件;所文件存在,寫入的數據會被加到文件尾,即文件原先的內容會被保留 - a+ 表示以附加的方式打開可讀寫的文件。若文件不存在,則會建立該文件;所文件存在,寫入的數據會被加到文件尾,即文件原先的內容會被保留 - 上述形態都可以再添加一個字符'b',表示打開二進制文件(POSIX 系統的 Linux 會忽略 b 字符);新建文件會有 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH(0666)權限 int fclose(FILE* stream); 成功返回0,失敗返回EOF ``` ### 3.2 流文件的讀寫操作 (fget & fputc & fputs & fwrite & fread) ```c #include <stdio.h> int fget(FILE* stream); // 成功返回讀取的字符,失敗返回EOF int fputc(int c, FILE* stream); // 成功返回寫入的字符,失敗返回EOF int fputs(const char* s, FILE* stream); // 成功返回寫出的字符個數,失敗返回EOF /* - ptr:將寫入的數據地址 - size:字符串長度 - nmemb:字符串數目 - stream:文件流 */ size_f fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream); // 成功返回實際寫入的 nmemb 數目,失敗返回 EOF size_t fread(const void* ptr, size_t size, size_t nmemb, FILE* stream); // 成功返回實際讀取到的 nmemb 數目,失敗返回 EOF ``` ### 3.3 文件的定位 (fseek & ftell & rewind) ```c /* 移動文件流的讀寫位置 stream 為文件流 whence 有以下幾種: - SEEK_SET 從距文件開頭 offset 位移量為新的讀寫位置 - SEEK_CUR 以目前的讀寫位置往后增加 offset(允許負值) 個位移量 - SEEK_END 將讀寫位置指向文件尾后再增加 offset(允許負值) 個位移量 */ int fseek(FILE* stream, long offset, int whence); // 調用成功返回0,有錯誤返回-1 // 取得文件流的讀取位置 long ftell(FILE* stream); // 成功返回當前讀寫位置,有錯誤返回-1 // 重設文件流的讀寫位置為文件開頭 void rewind(FILE* stream); ``` ## 4 特殊文件的操作 函數 | 作用 ---- | ---- opendir | 打開目錄文件 readdir | 讀取目錄文件 closedir | 關閉目錄文件 symlink | 建立軟鏈接 link | 建立硬鏈接 ### 4.1 目錄文件的操作 (opendir & readdir & closedir) ```c struct __dirstream { void *__fd; // hurd 指針 char *__data; // 文件夾塊 int __entry_data; char *_ptr; // 當前在塊中的指針 int __entry_ptr; size_t __allocation; size_t __size; __libc_lock_define (, __lock); }; typedef struct __dirstream DIR; struct dirent { ino_t d_ino; // 此目錄進入點的 inode 的節點號 ff_t d_off; // 目錄文件開頭至此目錄進入點的位移 signed short int d_reclen; unsigned char d_type; // 所指的文件類型 har d_name[256]; // 文件名,不包含 NULL 字符 }; ``` ```c #include <sys/types.h> #include <dirent.h> DIR* opendir(const char* name); // 成功返回目錄流,失敗返回NULL #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> struct dirent * readdir(DIR* dir); // 成功則返回下個目錄進入點,有錯誤發生或讀取到目錄文件尾則返回NULL #include <sys/types.h> #include <dirent.h> int closedir(DIR * dir); // 關閉成功返回0,失敗返回-1,錯誤原因存于errno中 ``` ### 4.2 鏈接文件的操作 (symlink & link) 軟鏈接(符號鏈接) | 硬鏈接 --- | --- 跨越不同文件系統 | 不支持跨越不同文件系統(例如/bin目錄和用戶目錄屬于不同的文件系統) 可以在目錄間建立 | 不可以給目錄建立硬鏈接 如果鏈接指向的文件從一個目錄移動到另一個目錄,就無法通過軟鏈接訪問(含有源文件在文件結構中的路徑信息) | 需要一個索引節點,需要占用空間 | 軟連接文件和源文件是不同類型的文件,也是不同的文件,inode號也不同 | 具有相同 inode 的文件互為硬鏈接文件 刪除源文件,鏈接文件依然存在,但是無法指向源文件 | 刪除硬鏈接文件或者刪除源文件任意一個,文件數據實際并未刪除;只有刪除源文件以及所對應的所有硬鏈接文件,文件數據才被刪除,同時釋放磁盤空間 ```c #include <unistd.h> /* 建立軟鏈接 - oldpath 已存在文件路徑和文件名(一定要存在,否則不生效) - newpath 鏈接的名稱 */ int symlink(const char* oldpath, const char *newpath); // 成功返回0,失敗返回-1,錯誤原因存于errno // 建立硬鏈接 int link(consta char* oldpath, const char *newpath); // 成功返回0,失敗返回-1,錯誤原因存于errno ``` ## 附錄 - [Linux文件系統及文件刪除原理](https://blog.csdn.net/weixin_45440548/article/details/104667469)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看