作者hth9494 (hth9494)
看板C_and_CPP
標題[問題] 檔案I/O緩衝區請益
時間Sun May 28 04:05:24 2017
開發平台(Platform): (Ex: Win10, Linux, ...)
Linux 3.16.0-4-586
編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
GCC
--
在敘述問題前,我想先說下到目前為止,我對檔案I/O方面理解到的一點東西。
理解不深,若有誤希望大家可以指正我,或給我一點線索,謝謝T_T。
以下的理解是建立在linux環境之下。
--
一、
C語言的文件讀寫函式,像是fgets, fread, fputc...等,是透過一個
FILE *類型的參數來操作,而最終這些函式會呼叫諸如read或write之類
的system call,完成文件讀寫。
二、
一個程式被load進記憶體時,內核會有一個PCB來記錄這個程式的
相關資訊,其中也會記錄這個程式所開啟的文件。代表著這些文件的是一些
整數,read或write也是用這些整數來當作參數,對相應的文件進行處理。
一個程式一開始會開啟三個文件,分別是stdin,stdout和stderr,對應
的整數分別是0,1,2。
FILE結構內_fileno的值其實就是這個整數的值。
三、
system call的I/O是 "unbuffered I/O"。
C函式庫的I/O是 "buffered I/O"。
假設我有支C如下
#include <stdio.h>
int main(void)
{
char str[20] = "Hello A.txt\n";
FILE *fpA = fopen("A.txt", "w");
fputs(str, fpA);
fclose(fpA);
return 0;
}
因為我調用了C函式fopen,所以C會幫我管理一塊專屬於A.txt的buffer,
關於buffer的資訊會記在fpA所指的FILE結構中。
buffer位於這支程式的記憶體空間內,在user space裡。
fputs的作用就是把str寫到這個user space的buffer中。
也就是說,其實執行完fputs時,str還沒真正被寫入A.txt,只在buffer而已。
(這是C的buffered I/O)
在kernel space裡,也有一個A.txt的buffer。
write的作用就是把user space的buffer資料寫到kernel space的buffer裡,
之後再寫回A.txt中。
(這是system call的unbuffered I/O,但我不知道為什麼叫unbuffered)
四、
如果資料被放在space buffer中且沒有做flush的動作,那資料就不會
被寫到文件裡。
例如這個C程式就會印不出字串
#include <stdio.h>
int main(void)
{
printf("Hello world"); //不會顯示在終端上
while (1);
return 0;
}
下面幾種行為會導致buffer flush
1、呼叫fflush
2、fclose
3、exit
--
以上是目前為止我對文件I/O的理解。
如果有錯希望大家可以教我一下,因為下面我要問的問題是建立在這
之上,結果搞不好其實我上面就錯的一蹋糊塗了。
--
一、
上面說到,因為我調用了C函式來操作I/O,所以C會幫我管理一個user space
的buffer,那麼,當我不用C標準函式庫,而直接使用system call來處理
文件的話,是不是就沒有那個 user space buffer了?
還有,那kernel space的buffer依然存在嗎?
例如這樣
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main(void)
{
char str[20] = "Hello A.txt\n";
int fdA = open("A.txt", O_WRONLY|O_CREAT, 0666);
write(fdA, str, strlen(str));
close(fdA);
return 0;
}
二、
一個程式開始前會先開啟stdin、stdout和stderr三個文件,那很多個程式
同時執行時,kernel space buffer是怎麼運作的?
例如有三個process,p1開啟這三個文件,p2、p3亦然,他們的user space各有
這三個文件的buffer,但是在kernel space中呢?也是各有三個buffer嗎?
讀寫的時候不會衝突嗎?
三、
當一個程式呼叫exit結束時,會關閉文件流並且flush user space的緩衝區,
請問kernel space的緩衝區會跟著被清空嗎?
四、
以下程式碼
#include <unistd.h>
#include <stdlib.h>
int main(void)
{
char buf[10];
int n;
n = read(STDIN_FILENO, buf, 10);
if (n < 0) {
perror("read STDIN_FILENO");
exit(1);
}
write(STDOUT_FILENO, buf, n);
return 0;
}
編譯成a.out並執行,結果是這樣
$ ./a.out
hello world
hello worl$ d
-bash: d: command not found
我能理解當我輸入hello world時,緩衝區內會有11個字元,而這支a.out只讀了
10個,所以緩衝區會剩一個d,但我不明白的是,為什麼a.out結束,返回shell後
shell還會讀到這個d,shell 和 a.out的緩衝區應該是分開的不是嗎? 而且a.out
結束後,也應該會清空緩衝區才對,我整個黑人問號,希望大家可以跟我解釋一下
這個現象,謝謝。
--
以下是我參考的資料,問題也是閱讀這些資料時蹦出來的。
http://docs.huihoo.com/c/linux-c-programming/ch28s04.html
http://blog.csdn.net/astrotycoon/article/details/44993197
問題有點多,如果有那裡覺得表達不清楚請跟我說下,我會再做補充。
總之感激不盡,謝謝大家T_T。
--
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 114.42.93.120
※ 文章網址: https://webptt.com/m.aspx?n=bbs/C_and_CPP/M.1495915530.A.B3A.html
1F:→ tinlans: 把 APUE 拿來讀一遍就行了 06/05 03:36
2F:推 galic: 補充一下,C的三個i/o stream和各自的buffer行為 規格書是 06/06 04:16
3F:→ galic: 有訂的 06/06 04:16
4F:→ galic: 然後你說得kernel buffer…建議先理解unix-like對於file的 06/06 04:16
5F:→ galic: 概念不是這麼單純 像是block和character device的定義等等 06/06 04:16