# 文件,第 1 部分:使用文件
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Files%2C-Part-1%3A-Working-with-files>
## 兩種類型的文件
在 linux 上,有兩個帶文件的抽象。第一個是 linux `fd`級抽象,意味著你可以使用
* `open`
* `read`
* `write`
* `close`
* `lseek`
* `fcntl` ......
等等。 linux 界面非常強大且富有表現力,但有時我們需要可移植性(例如,如果我們正在為 mac 或 windows 編寫)。這就是 C 的抽象發揮作用的地方。在不同的操作系統上,C 使用低級函數來創建可以在任何地方使用的文件的包裝器,這意味著 Linux 上的 C 使用上述調用。 C 有以下幾點
* `fopen`
* `fread`或`fgetc/fgets`或`fscanf`
* `fwrite`或`fprintf`
* `fclose`
* `fflush`
但是你沒有得到 linux 給你系統調用的表達能力,你可以使用`int fileno(FILE* stream)`和`FILE* fdopen(int fd...)`在它們之間來回轉換。
需要注意的另一個重要方面是 C 文件是**緩沖**,這意味著默認情況下可能無法寫入內容。您可以使用 C 選項更改它。
## 如何判斷文件有多大?
對于小于 long 的文件,使用 fseek 和 ftell 是一種簡單的方法來完成此任務:
移動到文件末尾并找出當前位置。
```c
fseek(f, 0, SEEK_END);
long pos = ftell(f);
```
這告訴我們文件中的當前位置(以字節為單位) - 即文件的長度!
`fseek`也可用于設置絕對位置。
```c
fseek(f, 0, SEEK_SET); // Move to the start of the file
fseek(f, posn, SEEK_SET); // Move to 'posn' in the file.
```
父進程或子進程中的所有未來讀取和寫入都將遵循此位置。注意從文件中寫入或讀取將改變當前位置。
有關更多信息,請參見 fseek 和 ftell 的手冊頁。
## 但盡量不要這樣做
**注意:由于 C 語言**的怪癖,在通常情況下不建議這樣做。這個怪癖是多頭只需要 **4 字節大**意味著 ftell 可以返回的最大大小略低于 2 千兆字節(我們現在知道我們的文件可能是幾百千兆字節甚至太字節數分布式文件系統)。我們該怎么做呢?使用`stat`!我們將在后面的部分介紹 stat,但這里有一些代碼可以告訴你文件的大小
```c
struct stat buf;
if(stat(filename, &buf) != -1){
return -1;
}
return (ssize_t)buf.st_size;
```
buf.st_size 的類型為 off_t,足夠 _ 瘋狂 _ 大文件。
## 如果子進程使用`fclose`或`close`關閉文件流會發生什么?
關閉文件流對每個進程都是唯一的。其他進程可以繼續使用自己的文件句柄。請記住,在創建子項時,甚至文件的相對位置都會復制所有內容。
## mmap for files 怎么樣?
mmap 的一般用途是將文件映射到內存。這并不意味著文件立即被 malloc'ed 到內存中。以下面的代碼為例。
```
int fd = open(...); //File is 2 Pages
char* addr = mmap(..fd..);
addr[0] = 'l';
```
內核可能會說,“好吧,我看到你想把文件映射到內存中,所以我會在你的地址空間中預留一些空間,即文件的長度”。這意味著當您寫入 addr [0]時,您實際上正在寫入文件的第一個字節。內核實際上也可以做一些優化。它不是將文件加載到內存中,而是一次只能加載頁面,因為如果文件是 1024 頁;您只能訪問 3 或 4 頁,這使得加載整個文件浪費時間(這就是頁面錯誤如此強大的原因!它們讓操作系統控制您使用文件的程度)。
## 對于每個 mmap
請記住,一旦完成`mmap` ping 您`munmap`告訴操作系統您不再使用已分配的頁面,因此操作系統可以將其寫回磁盤并在需要時將地址返回給您 malloc 以后。
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話