go 輸入輸出流 ioutil

2021-08-19 15:00:33 字數 3066 閱讀 8725

雖然 io 包提供了不少型別、方法和函式,但有時候使用起來不是那麼方便。比如讀取乙個檔案中的所有內容。為此,標準庫中提供了一些常用、方便的io操作函式。

說明:這些函式使用都相對簡單,一般就不舉例子了。

有時候我們需要傳遞乙個io.readcloser的例項,而我們現在有乙個io.reader的例項,比如:strings.reader,這個時候nopcloser就派上用場了。它包裝乙個io.reader,返回乙個io.readcloser,而相應的close方法啥也不做,只是返回nil。

比如,在標準庫net/http包中的newrequest,接收乙個io.reader的body,而實際上,request的body的型別是io.readcloser,因此,**內部進行了判斷,如果傳遞的io.reader也實現了io.readcloser介面,則轉換,否則通過ioutil.nopcloser包裝轉換一下。相關**如下:

rc, ok := body.(io.readcloser)

if !ok && body != nil

如果沒有這個函式,我們得自己實現乙個。當然,實現起來很簡單,讀者可以看看nopcloser的實現。

很多時候,我們需要一次性讀取io.reader中的資料,通過上一節的講解,我們知道有很多種實現方式。考慮到讀取所有資料的需求比較多,go提供了readall這個函式,用來從io.reader中一次讀取所有資料。

func readall(r io.reader) (byte, error)
閱讀該函式的原始碼發現,它是通過bytes.buffer中的readfrom來實現讀取所有資料的。

筆試題:編寫程式輸出某目錄下的所有檔案(包括子目錄)

是否見過這樣的筆試題?

在go中如何輸出目錄下的所有檔案呢?首先,我們會想到查os包,看file型別是否提供了相關方法(關於os包,後面會講解)。

其實在ioutil中提供了乙個方便的函式:readdir,它讀取目錄並返回排好序的檔案和子目錄名(os.fileinfo)。通過這個方法,我們可以很容易的實現「面試題」。

下面的例子實現了類似unix中的tree命令,不過它在windows下也執行的很好哦。

// 未實現-l引數功能

func main() )

}}// 列出dirname目錄中的目錄樹,實現類似unix中的tree命令

// curhier 當前層級(dirname為第一層)

// hiermap 當前層級的上幾層是否需要'|'的對映

func tree(dirname string, curhier int, hiermap map[int]bool) error

fileinfos, err := ioutil.readdir(dirabs)

if err != nil

filenum := len(fileinfos)

for i, fileinfo := range fileinfos else

fmt.print(strings.repeat(" ", 3))

}// map是引用型別,所以新建乙個map

tmpmap := map[int]bool{}

for k, v := range hiermap

if i+1 == filenum else

fmt.print("-- ")

fmt.println(fileinfo.name())

if fileinfo.isdir()

}return nil

}

readfile 讀取整個檔案的內容,在上一節我們自己實現了乙個函式讀取檔案整個內容,由於這種需求很常見,因此go提供了readfile函式,方便使用。readfile的是實現和readall類似,不過,readfile會先判斷檔案的大小,給bytes.buffer乙個預定義容量,避免額外分配記憶體。

writefile 函式的簽名如下:

func writefile(filename string, data byte, perm os.filemode) error
它將data寫入filename檔案中,當檔案不存在時會建立乙個(檔案許可權由perm指定);否則會先清空檔案內容。對於perm引數,我們一般可以指定為:0666,具體含義os包中講解。

小提示readfile 原始碼中先獲取了檔案的大小,當大小 < 1e9時,才會用到檔案的大小。按原始碼中注釋的說法是fileinfo不會很精確地得到檔案大小。

作業系統中一般都會提供臨時目錄,比如linux下的/tmp目錄(通過os.tempdir()可以獲取到)。有時候,我們自己需要建立臨時目錄,比如go工具鏈原始碼中(src/cmd/go/build.go),通過tempdir建立乙個臨時目錄,用於存放編譯過程的臨時檔案:

b.work, err = ioutil.tempdir("", "go-build")
第乙個引數如果為空,表明在系統預設的臨時目錄(os.tempdir)中建立臨時目錄;第二個引數指定臨時目錄名的字首,該函式返回臨時目錄的路徑。

相應的,tempfile用於建立臨時檔案。如gofmt命令的原始碼中建立臨時檔案:

f1, err := ioutil.tempfile("", "gofmt")
引數和ioutil.tempdir引數含義類似。

這裡需要注意:建立者建立的臨時檔案和臨時目錄要負責刪除這些臨時目錄和檔案。如刪除臨時檔案:

defer func() ()
discard 對應的型別(type devnull int)實現了io.writer介面,同時,為了優化io.copy到discard,避免不必要的工作,實現了io.readerfrom介面。

devnull 在實現io.writer介面時,只是簡單的返回(標準庫檔案:src/pkg/io/ioutil.go)。

func (devnull) write(p byte) (int, error)
而readfrom的實現是讀取內容到乙個buf中,最大也就8192位元組,其他的會丟棄(當然,這個也不會讀取)。

輸入輸出流

c 通過以下幾個類支援檔案的輸入和輸出 ofstream寫操作的檔案類由ostream引申而來 ifstream讀操作的檔案類由istream引申而來 fstream可同時讀寫操作的檔案類由iostream引申而來 ifstream in tian.txt 開啟乙個檔案 ifstream in in...

輸入輸出流

預定義流類的物件與通用的流運算子 1 cin 2 cout 3 cerr是ostream類物件,在標準輸出裝置上顯示錯誤資訊 不帶緩衝,立即顯示 輸入輸出流 ostream 和 ofstream istream 和 ifstream fstream 定義檔案輸出流物件 fstream outfile...

輸入輸出流

流 按照方向分為 輸入流和輸出流。以記憶體為參照物將資料從資料來源中讀取到記憶體,為輸入流,也叫讀取流。將資料從記憶體中寫入資料來源,為輸出流,也稱為寫入流 流按照型別分 分為位元組流,字元流和物件流。由於計算機採用二進位制,所有資料的傳輸都是以位元組為單位傳輸。所以無論是那種流,其本質都是位元組流...