2011-07-07 7 views
6

Czytam linie z pliku tekstowego, używając (line-seq (reader "input.txt")). Ta kolekcja jest następnie przekazywana i używana przez mój program.Używanie `line-seq` z` reader`, kiedy plik jest zamknięty?

Jestem zaniepokojony, że może to być zły styl, ponieważ nie deterministycznie zamykam plik. Wyobrażam sobie, że nie mogę użyć (with-open (line-seq (reader "input.txt"))), ponieważ strumień plików zostanie prawdopodobnie zamknięty, zanim przejdę całą sekwencję.

Czy należy unikać lazy-seq w połączeniu z plikami reader? Czy istnieje inny wzór, którego powinienem tu użyć?

Odpowiedz

15

Od tego tak naprawdę nie ma jasnej odpowiedzi (to wszystko miesza się do uwag dotyczących pierwszej odpowiedzi), oto esencja:

(with-open [r (reader "input.txt")] 
    (doall (line-seq r))) 

To zmusi całą sekwencję linii do odczytu i zamknij plik. Następnie możesz przekazać wynik całego tego wyrażenia.

Gdy mamy do czynienia z dużymi plikami, możesz mieć problemy z pamięcią (trzymając cały przebieg linii w pamięci) i wtedy jest to dobry pomysł, aby odwrócić ten program:

(with-open [r (reader "input.txt")] 
    (doall (my-program (line-seq r)))) 

Może lub nie może wymagać w tym przypadku, w zależności od tego, co mój program zwraca i/lub czy mój program leniwie lub nie leci.

0

Wygląda na to, że clojure.contrib.duck-streams/read-lines jest właśnie tym, czego szukasz. read-lines zamyka plik, gdy nie ma danych wejściowych i zwraca sekwencję podobnie jak line-seq. Spróbuj spojrzeć na kod źródłowy z read-lines.

+1

clojure.contrib.duck-streams jest przestarzałe: http://clojure.github.com/clojure-contrib/#duck-streams – pauldoo

+0

@pauldoo Nie zauważyłem tego. Masz rację, ale funkcje 'line-seq' i' read-line' używają tego samego wzorca do pobierania ciągów z czytnika (przez .readLine). Wystarczy spojrzeć na nie ([line-seq] (https://github.com/clojure/clojure/blob/f86db9cc68773dd3e4a166c1ff7b81e4a98aa602/src/clj/clojure/core.clj#L2314), [read-line] (https: // github.com/clojure/clojure-contrib/blob/aa3f018f65006c78b08703e7adef04b7f39e1542/src/main/clojure/clojure/contrib/duck_streams.clj#L236)), jeśli chcesz lenistwa, możesz pobrać 'read-line' do swojego kodu źródłowego. – m039

+0

@pauldoo Jak widzę, innym rozwiązaniem nie jest wykorzystanie lenistwa i pobranie całej zawartości do zmiennej lub po prostu użycie .close na czytniku. I powinieneś używać 'with-open' w ten sposób' (with-open [r (reader "input.txt")] (make-smth-on-lines (line-seq r)))) '. – m039