1. 程式人生 > >Linux 檔案IO: 緩衝與非緩衝

Linux 檔案IO: 緩衝與非緩衝

本地檔案IO一般都是同步阻塞的

本地普通檔案IO一般關注的是快取,一般都是同步阻塞的。普通檔案的file descriptor是block也是POSIX標準。這點不同於網路IO,網路IO要考慮傳輸兩邊程序處理等,設計之初就提供了帶狀態檢測的非同步操作方式,本地檔案IO則必然要求高可靠性的。

利用系統呼叫, unbuffered I/O

不帶緩衝指的是每個readwrite都呼叫了核心的一個系統呼叫。這些函式在呼叫的時候系統呼叫直接進行了磁碟檔案的寫入操作。

#include <string.h>
#include <unistd.h>

int main() {
    char
* buffer = "hello, world\n"; write(1, buffer, strlen(buffer)); return 0; }

打斷點可以看是直接呼叫的系統呼叫

(gdb) pt write
type = int ()
(gdb) bt
#0  write () at ../sysdeps/unix/syscall-template.S:81
#1  0x00000000004005ad in main () at main.c:6

利用C標準庫, buffered IO

標準IO提供快取的目的是儘可能減少使用read, write呼叫的數量。

標準IO庫處理很多細節,如快取分配,以優化長度執行I/O,是在系統呼叫函式基礎上構造的,便於使用者使用。標準IO函式fopen

返回一個指向FILE物件的指標。該物件管理該流所需要的所有資訊:用於實際IO的檔案描述符,指向流快取的指標,快取的長度,當前在快取中的字元數,出錯標誌等。

標準輸入、標準輸出和標準出錯這三個標準IO流通過預定義檔案指標 stdin, stdout, stderr 加以引用。這三個檔案指標同樣定義在標頭檔案<stdio.h>中。

如:函式fputs將一個以null符終止的字串寫到指定的流,終止符null不寫出。

#include <stdio.h>

int main() {
    char* buffer = "hello, world!\n";
    fputs
(buffer, stdout); return 0; }

打斷點看最終還是用的作業系統呼叫

(gdb) pt write
type = int ()
(gdb) bt
#0  write () at ../sysdeps/unix/syscall-template.S:81
#1  0x00007ffff7a8de53 in _IO_new_file_write (f=0x7ffff7dd4400 <_IO_2_1_stdout_>, data=0x7ffff7ff7000, n=14) at fileops.c:1261
#2  0x00007ffff7a8f32c in new_do_write (to_do=14, data=0x7ffff7ff7000 "hello, world!\n", fp=0x7ffff7dd4400 <_IO_2_1_stdout_>)
    at fileops.c:538
#3  _IO_new_do_write (fp=[email protected]=0x7ffff7dd4400 <_IO_2_1_stdout_>, data=0x7ffff7ff7000 "hello, world!\n", to_do=14)
    at fileops.c:511
#4  0x00007ffff7a8f703 in _IO_new_file_overflow (f=0x7ffff7dd4400 <_IO_2_1_stdout_>, ch=10) at fileops.c:876
#5  0x00007ffff7a9055c in __GI__IO_default_xsputn (f=[email protected]=0x7ffff7dd4400 <_IO_2_1_stdout_>, data=data@entry=0x400624,
    n=[email protected]=14) at genops.c:480
#6  0x00007ffff7a8e532 in _IO_new_file_xsputn (f=0x7ffff7dd4400 <_IO_2_1_stdout_>, data=<optimized out>, n=14) at fileops.c:1353
#7  0x00007ffff7a83614 in __GI__IO_fputs (str=0x400624 "hello, world!\n", fp=0x7ffff7dd4400 <_IO_2_1_stdout_>) at iofputs.c:40
#8  0x0000000000400593 in main () at main.c:5

其中stdout是標準庫定義的一個型別, 可以在標準庫原始碼看到, 也可以 gdb 看到起型別, 這個結構體中就有一個欄位是檔案描述符,也是1,可以很容易檢視

(gdb) pt stdout
type = struct _IO_FILE {
    int _flags;
    char *_IO_read_ptr;
    char *_IO_read_end;
    char *_IO_read_base;
    char *_IO_write_base;
    char *_IO_write_ptr;
    char *_IO_write_end;
    char *_IO_buf_base;
    char *_IO_buf_end;
    char *_IO_save_base;
    char *_IO_backup_base;
    char *_IO_save_end;
    struct _IO_marker *_markers;
    struct _IO_FILE *_chain;
    int _fileno;
    int _flags2;
    __off_t _old_offset;
    unsigned short _cur_column;
    signed char _vtable_offset;
    char _shortbuf[1];
    _IO_lock_t *_lock;
    __off64_t _offset;
    void *__pad1;
    void *__pad2;
    void *__pad3;
    void *__pad4;
    size_t __pad5;
    int _mode;
    char _unused2[20];
} *
(gdb) p stdout->_fileno
$1 = 1

一點有趣的地方, cd /usr/include/stdio.h 原始碼有下面一處註釋,very funny, make them happy :)

/* Standard streams.  */
extern struct _IO_FILE *stdin;          /* Standard input stream.  */
extern struct _IO_FILE *stdout;         /* Standard output stream.  */
extern struct _IO_FILE *stderr;         /* Standard error output stream.  */
/* C89/C99 say they're macros.  Make them happy.  */
#define stdin stdin
#define stdout stdout
#define stderr stderr

標準IO三種類型的快取

  1. 全快取。在這種情況下,當填滿標準IO快取後才進行實際IO操作。對於駐在磁碟上的檔案通常是由標準IO庫實施全快取的。
  2. 行快取。在這種情況下,當在輸入和輸出中遇到新行符時,標準IO庫執行IO操作。兩個限制:第一個是:因為標準IO庫用來收集每一行的快取的長度是固定的,所以只要填滿了快取,那麼即使還沒有寫一個新行符,也進行IO操作。第二個是:任何時候只要通過標準輸入輸出庫要求從(a)一個不帶快取的流,或者(b)一個行快取的流(它預先要求從核心得到資料)得到輸入資料,那麼就會造成重新整理所有行快取輸出流。
  3. 不帶快取。標準IO庫不對字元進行快取。相當於用write系統呼叫, 如標準出錯流stderr通常是不帶快取的,這就使得出錯資訊可以儘快顯示出來。

ANSI C要求下列快取特徵:
- 當且僅當標準輸入和標準輸出並不涉及互動作用裝置時,它們才是全快取的。
- 標準出錯決不會是全快取的。

相關推薦

Linux 檔案IO: 緩衝緩衝

本地檔案IO一般都是同步阻塞的 本地普通檔案IO一般關注的是快取,一般都是同步阻塞的。普通檔案的file descriptor是block也是POSIX標準。這點不同於網路IO,網路IO要考慮傳輸兩邊程序處理等,設計之初就提供了帶狀態檢測的非同步操作方式,本地

7-檔案IO-阻塞阻塞IO

1. 阻塞 IO 通常來說,從普通檔案讀資料,無論你是採用 fscanf,fgets 也好,read 也好,一定會在有限的時間內返回。但是如果你從裝置,比如終端(標準輸入裝置)讀資料,只要沒有遇到換行符(‘\n’),read 一定會“堵”在那而不返回。還有比如

Linux檔案的阻塞阻塞對部分系統呼叫的影響

1.基本概念 所謂的阻塞,即核心在對檔案操作I/O系統呼叫時,如果條件不滿足(可能需要產生I/O),則核心會將該程序掛起。非阻塞則是發現條件不滿足就會立即返回。此外需要注意的是非阻塞並不是輪詢,不然就和阻塞沒多大區別了,它只是呼叫不成功就直接返回了,不會在去看

緩衝I/O緩衝I/O(fopenopen系列函式區別)

在程式中,對於檔案的讀寫,程式執行時間主要消耗在I/O上。與讀寫記憶體相比,讀寫硬碟上的檔案慢很多;每次讀取/寫入檔案的內容很少的話,那麼程式執行時間主要消耗在I/O上了。因此有了緩衝I/O和非緩衝I

基本IO模型阻塞IO模型

cep 格式 img 元組 nbsp 方法 處理 ddr 請求 基本IO模型 普通套接字實現的服務端一次只能服務一個客戶端 普通套接字實現的服務端的瓶頸在於在沒有新的套接字來之前, 不能處理已經建立連接的套接字的請求。具體解釋如下: 服務器套接字開始監聽後,就可接受客戶端

Linux 檔案IO

Linux為每個開啟的檔案都返回一個FILE指標,這個FILE指標對應著緩衝指標buffer,指向8192B,這是為了避免頻繁的讀寫,提高讀寫效率。 每次向檔案中寫的資料都是先寫到緩衝區中的,等待以下條件達到後再重新整理緩衝區 重新整理緩衝區的條件 1.   &

Linux檔案IO操作

Linux檔案IO操作包括開啟(open),建立(create),讀(read),寫(write) 開啟open int open(const char *path, int oflags); int open(const char *path, int oflag

OpenGL單緩衝緩衝的區別

單快取和雙快取 在我們電腦中,螢幕中顯示的東西都會被放在一個稱為顯示快取的地方,在通常情況下我們只有一個這樣的緩衝區即單緩衝,在單緩衝中任何繪圖的過程都會被顯示在螢幕中,這也就是我們為什麼會看到閃爍。而所謂雙緩衝就是再這個顯示的緩衝區之外再建立一個不顯示的緩衝區,我們所有的繪圖都將在這個

漫談linux檔案IO--io流程講的很清楚

這篇文章寫的比較全面,也淺顯易懂,備份下。轉載自:http://blog.chinaunix.net/uid-27105712-id-3270102.html 在Linux 開發中,有幾個關係到效能的東西,技術人員非常關注:程序,CPU,MEM,網路IO,磁碟IO。本篇檔案打算詳細全面,深入

Linux檔案IO快取總結

檔案IO快取 使用者空間快取(堆)—IO系統呼叫(write等)—核心空間快取記憶體—磁碟 write後立即返回,後續核心將快取區資料寫入磁碟 read從核心快取記憶體中讀取 設計目的:無需等待磁碟操作,減少磁碟操作 大塊快取空間,更少的系統呼叫,提高IO效能

Linux--檔案IO中幾點注意的地方

檔案IO中幾點注意的地方 一、open函式 開啟存在並有內容的檔案時可用選項:O_APPEND、O_TRUNC (1)I0檔案指標在檔案開頭,新內容寫在前面,依次覆蓋舊的內容: open("a.txt", O_RDWR); (2)檔案指標被設定到檔案底部,

【計算】單緩衝緩衝

題目:假設磁碟塊與緩衝區大小相同,每個盤塊讀入緩衝區的時間為10μs,由緩衝區送至使用者區的時間是5μs,系統對每個磁碟塊資料的處理時間為2μs。若使用者需要將大小為10個磁碟塊的Docl檔案逐塊從磁碟讀入緩衝區,並送至使用者區進行處理,那麼採用單緩衝區需要花費的時間為( )μs;採用雙緩衝區需

漫談linux檔案IO

    在Linux 開發中,有幾個關係到效能的東西,技術人員非常關注:程序,CPU,MEM,網路IO,磁碟IO。本篇檔案打算詳細全面,深入淺出。剖析檔案IO的細節。從多個角度探索如何提高IO效能。本文儘量用通俗易懂的視角去闡述。不copy核心程式碼。    

Linux檔案IO和標準IO

Linux 檔案IO Linux中做檔案IO最常用到的5個函式是: open , close , read , write 和 lseek ,不是ISO C的組成部分,這5個函式是不帶緩衝的IO,也即每個read和write都呼叫了核心的一個系統呼叫。 #includ

Linux Shell Bash 互動互動式指令碼

互動式的shell會在tty上從使用者輸入中讀取命令. 另一方面, 這樣的shell能在啟動時讀取啟動檔案, 顯示一個提示符, 並預設啟用作業控制. 也就是說, 使用者可以與shell互動. shell所執行的指令碼通常都是非互動的shell. 但是指令碼仍然可以訪問它的tty. 甚至可以在指令碼中模擬一

linux檔案內容查詢vim工具的使用

linxu命令非常的多,並且帶了很多引數,以完成不同的需求。這裡僅僅介紹,我自己比較常用的一些命令,更多的細節,可以參考(man 命令)或者閱讀《鳥哥的linux私房菜》。 1.cat命令,tac命令:cat命令和tac命令剛好相反,cat命令是從第一行到最後一行顯示,而t

Linux 檔案(vi/vim)目錄管理

Linux的目錄結構為樹狀結構,最頂級的目錄為根目錄 / 【詳情檢視】 處理目錄的常用命令 ls: 列出目錄 -a :全部的檔案,連同隱藏檔( 開頭為 . 的檔案) 一起列出來(常用) -d :僅列出目錄本身,而不是列出目錄內的檔案資料(常

Linux檔案、目錄磁碟格式

檔案系統特性: Linux的正規檔案系統為Ext2。其包含三個資料: super block : 記錄此檔案系統的整體資訊,包括inode/block的總量,使用量,剩餘量,以及檔案系統的格式與相關資訊等 inode: 記錄檔案的屬性,一個檔案佔用一個in

Linux檔案的檢視許可權

##檔案的檢視## ls -l filename   — ————       —    —      ——   —    ——————       —— 1          2               3      4           5     6     

linux 檔案io常用操作總結

對檔案的操作,究根結底也就是那麼幾種行為,分別為開啟,讀,寫,關閉。 一、檔案描述符:至於什麼是檔案描述符,這個是很簡單的概念。 二、開啟檔案 open(path,flag,...) 1、建立新