read與fread的區別

2021-08-10 07:53:27 字數 2236 閱讀 6790

與 fread 的區別的誤解" rel="noopener noreferrer">read 與 fread 的區別的誤解

刻卜浪興

前多時間梳理了一些linux上的程式設計,其實就是認識的大量的系統呼叫(posix)。這裡有乙個我們經常提出的問題就是fread,read的區別。(當然這兩個分別代表了操作檔案系統的兩套不同的函式,包括open,read,write, seek 等)。我們都知道,他們的區別就是乙個(read)是unix中的系統呼叫,是類unix系統,提供給程式設計師操作檔案的介面(要不然你如何操作檔案?);而另外乙個則是c語言提供的讀取檔案的函式庫,自然這個函式庫(ansi)的實現是以對應的系統呼叫為基礎的。

那麼為什麼c語言的函式庫需要向我們提供這樣的包裝,而其他的系統呼叫(像程序、執行緒管理與通訊等等)沒有這樣的包裝呢?

這當然是有原因的,也就是我們常說的有緩衝讀寫和無緩衝讀寫。

但是,我們進一步學習了unix系統中,直接i/o的概念之後,對上面的了解需要更深一步了。

為什麼要緩衝?

我們先不管使用者態、核心態這些事情,我們先思考,讀取外設上的檔案為什麼需要緩衝。

(我們知道,一般意義上流的概念已經被使用到了檔案讀寫中,這個概念與緩衝的概念沒有關係。)

我們使用函式向某個檔案從當前流標籤所在位置,讀取n個字元。我們也會使用函式向檔案的某個流位置寫如n字元。但是,當這種寫的動作小、而頻繁。每次寫又必須反映到硬碟上,也就是說需要頻繁的操作硬碟,寫一些小的更改,這是非常耗損效率。所以自然我們想到了,我們設立乙個緩衝區,將那些要寫入的資料先寫到緩衝區中,當緩衝區滿,或者其他情況發生的時候,我們在一起將他們寫入到硬碟上。這樣可以大大提高應用程式讀寫檔案的速度。

這就是為什麼需要緩衝,根本原因我認為是磁碟等外設的資料還和記憶體的速度相差甚遠,所以我們不希望由於操作外設的原因讓本來很快的記憶體和cpu跟著一起慢,我們想的辦法:一是非同步寫(但這有時候不能符合應用要求),二就是緩衝讀寫。

而我們通常所理解的就是,read體系,就是那種無緩衝讀寫,不管是讀還是寫,呼叫這個體系的函式,會馬上啟動一次外設操作,讀取資料或者寫入資料。而fread體系則,使用了緩衝讀寫的方式,一定時間才呼叫read體系的函式。

上面的認識,事實上可以一定程度上說明問題的。但是,我們也太低估unix系統的智商了,要知道,不只是應用程式需要與外設進行互動,作業系統更是要與外設頻繁的互動。(事實上應用程式是通過作業系統與外設互動的,所以就有了使用者態和核心態概念)。

我們知道,應用程式要讀寫檔案,一般是通過作業系統的(這樣才發揮了作業系統管理系統的各項硬軟體的功能)。讀寫的過程並不是直接將外設中的資料,直接往使用者應用程式的空間傳送(雖然理論上好像可以,核心還不能往使用者空間寫資料?但是這不符合這種隔離的思想),而是首先由核心發出外設操作,將資料傳送到核心空間中(dma技術),然後從核心傳送的使用者空間中。這樣的好處就是能夠隔離開應用程式與硬體裝置的直接交流(那會導致應用軟體設計的複雜都增長)。但是這也導致了我們通常說的「多拷貝」問題。

在作業系統核心的管理下,資料想要從乙個檔案到另外乙個檔案,需要經過:

檔案1(外設)——>核心空間——>使用者空間——>核心空間——檔案2(外設)。

這裡還是假設使用者空間裡面該資料沒有拷貝動作,我們可以看到,中間的拷貝過程全部發生在記憶體中,只是分在核心與使用者的區別。

這種樣的過程其實是傷害效率的,但是如果不是對讀寫效率的要求過於苛刻,仍然使用這種方法。

事實上,read體系也有自己的緩衝機制,但是我們可以通過設定(open函式中direct標誌),放棄這種方式。

我們可以說,fread是在使用者應用程式空間中,自己建立了乙個緩衝機制,這種緩衝機制和核心read的緩衝機制並不衝突。

事實上,當我們使用read體系的時候,我們放棄了應用程式空間中的緩衝機制,但是如果不設定direct標誌,核心中的緩衝機制依然存在。

我們還有一種特殊的讀寫應用程式,叫著自緩衝讀寫,其實fread就是這樣一種方式。只是它沒有放棄核心的緩衝機制。但是對於複雜應用程式,例如資料庫,這種對讀寫效率要求高的地方,他們使用了自己定義緩衝機制並且毅然放棄了核心的緩衝方式,為什麼呢?因為核心緩衝方式,對緩衝資料何時應該存入到硬碟上,哪些資料應該留下來更久沒有應用背景相關的資訊,所以它所出來的決策,通常是盲目的。但是,如果應用程式自己設定這種緩衝,可以很大程度上彌補這一問題。

緩衝i/o絕對有它的好處,這種機制的使用不僅在使用者空間中,也在核心實現時會使用。當然有時候我們為了追求某些特別的需求,會使用直接i/o方式。當然事實上,這種i/o方式與緩衝與否不是對立的。但是往往這樣做了之後,緩衝就不夠。我們要使用直接i/o要慎重考慮,你應用程式的需求,例如,你需要訪問大塊資料。這個是否「多拷貝」無疑是乙個問題。其中取捨需要仔細考慮、權衡。

read 與 fread 的區別的誤解

前多時間梳理了一些linux上的程式設計,其實就是認識的大量的系統呼叫 posix 這裡有乙個我們經常提出的問題就是fread,read的區別。當然這兩個分別代表了操作檔案系統的兩套不同的函式,包括open,read,write,seek 等 我們都知道,他們的區別就是乙個 read 是unix 中...

read和fread的區別與使用

函式原型 ssize t read int fd void buf,size t count read用於從檔案描述符對應的檔案讀取資料,呼叫成功返回讀出的位元組數 buf為讀出資料的緩衝區,count為每次讀取的位元組數,出錯返回 1,結束返回0。函式原型 size t fread void pt...

fread 和 read函式的區別

1,fread是帶緩衝的,read不帶緩衝.2,fopen是標準c裡定義的,open是posix中定義的.3,fread可以讀乙個結構.read在linux unix中讀二進位制與普通檔案沒有區別.4,fopen不能指定要建立檔案的許可權.open可以指定許可權.5,fopen返回指標,open返回...