2015-01-14 5 views
4

С целью чтения текстового файла по строкам, без загрузки всего файла в память, какой общий способ сделать это в Rebol?В Rebol, что такое идиоматический способ чтения текстового файла по строкам?

Я делаю следующее, но я думаю, что (поправьте меня, если я ошибаюсь), что он загружает весь файл в память первым:

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

ответ

5

По крайней мере, с 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 
    ] 
] 

Вероятно, набора: слово линии части и попытку должна быть более подробно, с тем чтобы избежать конфликтов имен и получить значимые ошибки.

+0

Но не 'открытые/линий/direct' загружать весь файл в память? Это то, чего я пытаюсь избежать, по моему вопросу. – mydoghasworms

+1

Нет, 'open делает именно это - открывает файл. В то время как чтение читает. Ну, может быть, 'open bufferst в некоторых режимах, но есть также режим поиска, который вы могли бы использовать - http://www.rebol.com/article/0199.html – pekr

+2

Из личного опыта я могу подтвердить, что open/lines/direct может использовать меньше памяти, чем открытые/линии. Но вы увидите разницу просто, если вы откроете большие файлы. Вероятно, существует минимальный внутренний буфер, который будет всегда заполняться первым. – sqlab

2

Да open - это путь. Однако как sqlab касается необходимых /lines & /direct уточнений нет в Rebol 3 open (все же).

Хорошая новость, хотя в том, что вы все еще можете использовать open to read in large files в Rebol 3 без этих уточнений ...

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 
+0

Это довольно много кода. Я надеялся сделать что-то вроде Ruby: 'open ('file.txt'). Each {| line | puts line} '. Я думаю, можно было бы написать вариант функции foreach в Rebol, чтобы сделать что-то подобное, которое принимает файл или порт. Можете ли вы изменить поведение стандартных функций в противном случае? (Например, пусть 'foreach' принимает' порт! '? – mydoghasworms