Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Rebol, what is the idiomatic way to read a text file line by line?

Tags:

rebol

For the purpose of reading a text file line by line, without loading the entire file into memory, what is the common way to do this in Rebol?

I am doing the following, but I think (correct me if I'm wrong) that it loads the whole file into memory first:

foreach line read/lines %file.txt [ print line ]
like image 276
mydoghasworms Avatar asked Mar 17 '23 09:03

mydoghasworms


2 Answers

At least with Rebol2

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

should come near to what you want

but if you want all lines one line after the other, it should be like

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

In theory you can supersede any function, even natives. I will try to give a new 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
    ]
]

Probably the set :word line part and the attempt should be more elaborated in order to avoid name clashes and get meaningful errors.

like image 193
sqlab Avatar answered May 16 '23 07:05

sqlab


Yes open is the way to go. However like sqlab touches on the necessary /lines & /direct refinements are not present in Rebol 3 open (yet).

The good news though is that you can still use open to read in large files in Rebol 3 without these refinements...

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

So you just need to wrap this up into a buffer and process a line at a time.

Here's a crude working example I've put together:

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
like image 23
draegtun Avatar answered May 16 '23 06:05

draegtun