如何控制Scanf.Scanning的缓冲区?

问题描述:

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的当前阅读位置。”

我会很感激在什么地方正是这种行为 记录。

就一般的设计原则而言,我会说对Scanf.Scanning.from_channel的呼叫将通道的责任移动到Scanf模块。如果您在Scanf模块的背后并直接操作频道(如您在seek_in中所做的那样),则无法保证正常工作。

事情与我用过的几乎每个分层I/O库的工作类似。例如,你不能使用来自Unix stdio的fdopen(),并希望通过FILE抽象读取数据,同时也以任意方式操作底层文件描述符。

如果文档提到了这些问题(在这两种情况下),这可能会很好。

+0

我正在阅读大部分二进制文件,因此大部分时间都不需要“Scanf”。 –

+0

您可以尝试将文本读入缓冲区,然后使用'sscanf'。根据我的经验,'sscanf'比使用频道扫描更容易使用,更加可靠。几十年来我没有在生产代码中使用过scanf。如果你的文本很简单,你也可以使用'int_of_string'等。 FWIW。 –