2017-02-18 113 views
0

Scanf模塊似乎表現得稍微 違反直覺的,因爲它不尊重 底層信道的狀態:如果該通道被重建如何控制Scanf.Scanning的緩衝區?

(* prepare test data *) 
let() = 
    let oc = open_out "test.txt" in 
    output_string oc "abcdefghij\n"; 
    close_out oc 
;; 

let ic = open_in "test.txt" 

(* ic at offset 0: 「ab…」 *) 
let() = 
    let sc = Scanf.Scanning.from_channel ic in 
    let s = Scanf.bscanf sc "%2s" (fun s -> s) in 
    Printf.eprintf "read [%s]\n" s (* -> [ab] *) 
;; (* sc out of scope at this point *) 

(* hint: close ic here and reopen for expected result *) 
seek_in ic 4 

(* ic at offset 4: 「ef…」 *) 
let() = 
    let sc = Scanf.Scanning.from_channel ic in 
    let s = Scanf.bscanf sc "%2s" (fun s -> s) in 
    Printf.eprintf "read [%s]\n" s (* -> [cd] ‽ *) 
;; 

close_in ic 

顯然的Scanning.t內部緩衝器生存它 。有另一種方法來強制重新同步 ?該docs 聲稱「讀書開始於IC的當前閱讀位置。」

我會很感激在什麼地方正是這種行爲 記錄。

回答

0

就一般的設計原則而言,我會說對Scanf.Scanning.from_channel的呼叫將通道的責任移動到Scanf模塊。如果您在Scanf模塊的背後並直接操作頻道(如您在seek_in中所做的那樣),則無法保證正常工作。

事情與我用過的幾乎每個分層I/O庫的工作類似。例如,你不能使用來自Unix stdio的fdopen(),並希望通過FILE抽象讀取數據,同時也以任意方式操作底層文件描述符。

如果文檔提到了這些問題(在這兩種情況下),這可能會很好。

+0

我正在閱讀大部分二進制文件,因此大部分時間都不需要「Scanf」。 –

+0

您可以嘗試將文本讀入緩衝區,然後使用'sscanf'。根據我的經驗,'sscanf'比使用頻道掃描更容易使用,更加可靠。幾十年來我沒有在生產代碼中使用過scanf。如果你的文本很簡單,你也可以使用'int_of_string'等。 FWIW。 –