【golang系統編程】通用IO模型

全部執行I/O操做的系統調用,都使用一個非負整數(文件描述符)來描述打開的文件(文件、管道、socket、終端、設備)。
常見的3種文件描述符:
文件描述符 用途 POSIX名稱 stdio流
0 標準輸入 STDIN_FILENO stdin
1 標準輸出 STDOUT_FILENO stdout
2 標準錯誤 STDERR_FILENO stderr
通用IO模型的4個系統調用
下面的四個系統調用爲c語言的形式
  • fd = open(pathname, flags, mode):pathname是打開的文件名,flags指定文件的打開方式,mode指定文件的訪問權限,返回的fd爲上文所說的文件描述符
  • num = read(fd, buffer, count):從buffer中讀取至多n個字節的數據
  • num = write(fd, buffer, count):從buffer中寫入至多n個字節的數據,返回num可能小於count(不清楚什麼狀況)
  • status = close(fd)
在golang中,咱們也能夠經過標準庫syscall包使用系統調用
  • func Open(path string, mode int, perm uint32) (fd int, err error)
  • func Read(fd int, p []byte) (n int, err error)
  • func Write(fd int, p []byte) (n int, err error)
  • func Close(fd int) (err error)

可見golang的系統調用沒有count參數,默認Buffer的大小爲count的長度。golang

下面是一段代碼,用來進行文件的複製,沒有檢查所有的errorsocket

func Copy(oldFile, newFile string) {
    inputFd, err := syscall.Open(oldFile, os.O_RDONLY, 0666)
    if err != nil {
        panic(err)
    }

    // 此處用到了部分flags指定文件的打開方式,mode指定文件的訪問權限下一篇繼續
    outputFd, err := syscall.Open(newFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0666)
    if err != nil {
        panic(err)
    }

    defer syscall.Close(inputFd)
    defer syscall.Close(outputFd)

    buff := make([]byte, 10)
    for {
        size, _ := syscall.Read(inputFd, buff)
        if size == 0 {
            break
        }
    
        syscall.Write(outputFd, buff[:size])

    }
}
系統調用的詳細
open()

open函數會返回下面這些錯誤:函數

  • syscall.EACCES:文件權限不容許以指定的flags參數打開文件。可能的緣由有目錄權限的限制、文件不存在而且沒法建立
  • syacall.EISDIR:調用者企圖打開目錄對該文件進行寫操做
  • syscall.EMFILE:進程打開的文件描述符數量達到了進程資源限制的上限
  • syscall.ENFILE:文件打開的數量達到了系統容許的上限(EMFILE是進程上限)
  • syscall.ENOENT:文件或路徑不存在,且沒指定O_CREAT標誌(這個錯誤比較常見)
  • syscall.EROFS:企圖以寫方式打開了只讀文件
  • syscall.ETXTBSY:指定文件爲可執行文件且正在運行,系統不容許正在運行的程序

在系統調用中存在一個Create的系統調用,不過在golang中,這個func Creat(path string, mode uint32) (fd int, err error)是使用open()這個系統調用實現的。ui

read()

read調用成功,將返回實際讀取的字節數,若是文件結束(EOF)則返回0操作系統

write()

num, err := syscall.Write(fd, buff),num爲寫入的數量,通常等於len(buff),當num<len(buff),這就被稱爲"部分寫",多是磁盤不足,write的調用成功不表明寫入數據成功。指針

lseek():改變文件的偏移量

操做系統會保存打開文件的偏移量(也稱讀寫偏移量或指針)。只適用於文件。code

lssek在golang中爲func Seek(fd int, offset int64, whence int) (off int64, err error)進程

fd: 文件描述符
offset: 文件偏移量
whence: 按照什麼基點解釋offset參數資源

whenceinput

  • SEEK_SET: io.SeekStart,從文件頭部開始offset個字節
  • SEEK_CUR: io.SeekCurrent,從當前文件偏移量起offset個字節
  • SEEK_END: io.SeekEnd,文件尾起offset個字節

文件空洞

場景:當文件的偏移量超過了文件結尾

  • read: 返回0,表示讀到文件結尾
  • write: 能夠在文件結尾任意位置寫入數據

從文件結尾到新寫入的數據的開始位置的這一段空間被稱爲文件空洞

文件空洞不佔用任何磁盤空間,知道持續某個點,在文件空洞寫入了數據系統纔會被磁盤分配磁盤塊。文件空洞的優點在於:與實際須要的空字節分配磁盤相比,稀疏填充的文件佔用更小的磁盤空間。不支持文件空洞的系統會將空字節寫入到文件。存在文件空洞意味名義上的大小要比佔用的磁盤存儲總量要大

相關文章
相關標籤/搜索