【问题标题】:In Rebol, what is the idiomatic way to read a text file line by line?在 Rebol 中,逐行读取文本文件的惯用方式是什么?
【发布时间】:2015-01-14 09:25:41
【问题描述】:

为了逐行读取文本文件,而不是将整个文件加载到内存中,Rebol 中常用的方法是什么?

我正在执行以下操作,但我认为(如果我错了,请纠正我)它首先将整个文件加载到内存中:

foreach line read/lines %file.txt [ print line ]

【问题讨论】:

    标签: rebol


    【解决方案1】:

    至少在 Rebol2 中

    read/lines/direct/part %file.txt 1 
    

    应该接近你想要的

    但是如果你想让所有的行一个接一个,它应该像

    f: open/lines/direct %test.txt
    while [l: copy/part f 1] [print l]
    

    理论上你可以取代任何函数,甚至是原生函数。我会尝试给一个新的foreach

    foreach_: :foreach
    foreach:  func [
        "Evaluates a block for each value(s) in a series or a file for each line."
        'word [get-word! word! block!] {Word or block of words to set each time (will be local)}
        data [series! file! port!] "The series to traverse"
        body [block!] "Block to evaluate each time"
        /local port line
    ] [
        either any [port? data   file? data] [
            attempt [
                port: open/direct/lines data
                while [line:  copy/part port 1] [
                    set :word line
                    do :body 
                    line
                ]
            ] 
            attempt [close port]
        ] [
            foreach_  :word :data :body
        ]
    ]
    

    可能是 set :word line 部分,并且尝试应该更加详细,以避免名称冲突并获得有意义的错误。

    【讨论】:

    • 但是open/lines/direct 不是将整个文件加载到内存中吗?根据我的问题,这就是我要避免的。
    • 不,'open 就是这样做的——打开文件。而 'read 读取它。好吧,也许'在某些模式下打开缓冲区,但也有'你可以使用的搜索模式 - rebol.com/article/0199.html
    • 根据个人经验,我可以确认,open/lines/direct 可以比 open/lines 使用更少的内存。但是,如果您打开更大的文件,您会看到差异。可能使用了一个最小的内部缓冲区,它总是首先被填充。
    • 我在一些巨大(大于内存)的文件上使用 open/direct/lines,它只是按预期工作,不会将整个文件加载到内存中。
    • 就像我在对 draegtun 的评论中所说的那样:我希望在 Ruby 中执行以下操作:open('file.txt').each {|line| puts line}。我想人们可以在 Rebol 中编写 foreach 函数的变体来执行类似的接受文件或端口的操作。你能改变标准函数的行为吗? (例如让foreach 接受port!)?
    【解决方案2】:

    是的open 是要走的路。然而,像 sqlab 一样,必要的 /lines/direct 改进在 Rebol 3 open 中不存在(目前)。

    不过好消息是,如果没有这些改进,您仍然可以在 Rebol 3 中使用 open to read in large files...

    file: open %movie.mpg
    while [not empty? data: read/part file 32000] [
        ;
        ; read in 32000 bytes from file at a time
        ; process data
    ]
    close file
    

    因此,您只需将其包装到缓冲区中并一次处理一行。

    这是我整理的一个粗略的工作示例:

    file: open/read %file.txt
    eol: newline
    buffer-size: 1000
    buffer: ""
    lines: []
    
    while [
        ;; start buffering
        if empty? lines [
            ;; fill buffer until we have eol or EOF
            until [
                append buffer to-string data: read/part file buffer-size
                any [
                    empty? data
                    find buffer eol
                ]
            ]
            lines: split buffer eol
            buffer: take/last lines
        ]
    
        line: take lines
        not all [empty? data empty? buffer]
      ][
        ;; line processing goes here!
        print line
    ]
    
    close file
    

    【讨论】:

    • 那是相当多的代码。我希望在 Ruby 中执行以下操作:open('file.txt').each {|line| puts line}。我想可以在 Rebol 中编写 foreach 函数的变体来执行类似的接受文件或端口的操作。你能改变标准函数的行为吗? (例如让foreach 接受port!
    猜你喜欢
    • 1970-01-01
    • 2011-12-23
    • 2021-12-08
    • 2019-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-01
    相关资源
    最近更新 更多