2017-08-23 14 views
1

我正在使用第三方庫來生成PDF。爲了在最後編寫PDF(在使用lib的API添加完所有內容之後),pdfWriter類型的Write函數的期望值爲io.WriteSeeker使用不帶文件的io.WriteSeeker進入

這是好的,如果我想處理文件,但我需要在內存中工作。麻煩的是,我找不到任何方法來做到這一點 - 我發現實現io.WriteSeeker的唯一本機類型是File。

這是由pdfWriterWrite功能使用Fileio.Writer工作的一部分:

fWrite, err := os.Create(outputPath) 
if err != nil { 
    return err 
} 

defer fWrite.Close() 

err = pdfWriter.Write(fWrite) 

有沒有辦法做到這一點沒有實際的文件?就像獲得[]byte什麼的?

回答

4

不幸的是,在標準庫中沒有針對內存中的io.WriteSeeker實現的現成解決方案。

但是和往常一樣,你可以隨時實現你自己的。這並不難。

io.WriteSeekerio.Writerio.Seeker,所以基本上你只需要實現2種方法:

Write(p []byte) (n int, err error) 
Seek(offset int64, whence int) (int64, error) 

閱讀他們的資料,他們應該如何表現這些方法的一般合同。

這是一個簡單的實現,它使用內存中的字節片([]byte)。它沒有針對速度進行優化,這只是一個「演示」實現。

type mywriter struct { 
    buf []byte 
    pos int 
} 

func (m *mywriter) Write(p []byte) (n int, err error) { 
    minCap := m.pos + len(p) 
    if minCap > cap(m.buf) { // Make sure buf has enough capacity: 
     buf2 := make([]byte, len(m.buf), minCap+len(p)) // add some extra 
     copy(buf2, m.buf) 
     m.buf = buf2 
    } 
    if minCap > len(m.buf) { 
     m.buf = m.buf[:minCap] 
    } 
    copy(m.buf[m.pos:], p) 
    m.pos += len(p) 
    return len(p), nil 
} 

func (m *mywriter) Seek(offset int64, whence int) (int64, error) { 
    newPos, offs := 0, int(offset) 
    switch whence { 
    case io.SeekStart: 
     newPos = offs 
    case io.SeekCurrent: 
     newPos = m.pos + offs 
    case io.SeekEnd: 
     newPos = len(m.buf) + offs 
    } 
    if newPos < 0 { 
     return 0, errors.New("negative result pos") 
    } 
    m.pos = newPos 
    return int64(newPos), nil 
} 

是的,就是這樣。

測試它:

my := &mywriter{} 
var ws io.WriteSeeker = my 

ws.Write([]byte("hello")) 
fmt.Println(string(my.buf)) 

ws.Write([]byte(" world")) 
fmt.Println(string(my.buf)) 

ws.Seek(-2, io.SeekEnd) 
ws.Write([]byte("k!")) 
fmt.Println(string(my.buf)) 

ws.Seek(6, io.SeekStart) 
ws.Write([]byte("gopher")) 
fmt.Println(string(my.buf)) 

輸出(嘗試在Go Playground):

hello 
hello world 
hello work! 
hello gopher 

東西可以改善:

  • 創建mywriter值與初始爲空buf切片,但其容量很可能會覆蓋結果PDF文檔的大小。例如。如果你估計結果PDF文件是大約1 MB,創建具有容量的緩存爲2 MB這樣的:
    my := &mywriter{buf: make([]byte, 0, 2<<20)}

  • mywriter.Write()時需要能力有待提高(與現有的內容複製過來),也可能是有利可圖使用更大的增量,例如在一定程度上增加了現有產能的兩倍,這爲未來的追加保留了空間並使重新分配最小化。

+1

多麼真棒的答案,謝謝。小評論:在SeekEnd案例中,您需要增加偏移量,而不是減去偏移量。查看stdlib的reader.go以供參考。由於我在幾個項目中使用了這個功能,因此我將它編入了一個lib文件,並在許可證和自述文件中給了您相當的評價。檢查出來:https://github.com/orcaman/writerseeker – orcaman

+1

@orcaman你是對的,修正它在我的例子。 – icza

相關問題