with-openMakro dba, że czytelnik jest zamknięta na końcu korpusu. Funkcja czytnika przekształca ciąg (może również wykonać adres URL itp.) Do pliku BufferedReader. line-seqdostarcza leniwy seq. Żądanie kolejnego elementu leniwego ciągu powoduje odczytanie wiersza przez czytelnika.
Zwróć uwagę, że począwszy od Clojure 1.7 możesz także używać przetworników do czytania plików tekstowych.
Numer 3: jak pisać do nowego pliku.
(use 'clojure.java.io)(with-open [wrtr (writer "/tmp/test.txt")](.write wrtr "Line to be written"))
Ponownie, uważaj, with-openaby BufferedWriterna końcu korpusu był zamknięty. Writer przekształca ciąg w ciąg BufferedWriter, którego używasz przez java interop:(.write wrtr "something").
Możesz także użyć spitodwrotności slurp:
(spit "/tmp/test.txt""Line to be written")
Numer 4: dołącz linię do istniejącego pliku.
(use 'clojure.java.io)(with-open [wrtr (writer "/tmp/test.txt":append true)](.write wrtr "Line to be appended"))
To samo co powyżej, ale teraz z opcją dołączania.
Albo znowu z spitprzeciwieństwem slurp:
(spit "/tmp/test.txt""Line to be written":append true)
PS: Aby być bardziej precyzyjnym co do faktu, że czytasz i zapisujesz do File, a nie do czegoś innego, możesz najpierw utworzyć obiekt File, a następnie przekształcić go w BufferedReaderlub Writer:
Bardzo dziękuję za szczegółową odpowiedź. Cieszę się, że mogłem poznać zalecany sposób File IO (plik tekstowy) w 1.3. Wydaje się, że istniały biblioteki związane z File IO (clojure.contrb.io, clojure.contrib.duck-streams i kilka przykładów bezpośrednio używających Java BufferedReader FileInputStream InputStreamReader), co sprawiło, że byłem bardziej zagmatwany. Ponadto niewiele jest informacji o Clojure 1.3, zwłaszcza w języku japońskim (mój język naturalny). Dziękuję.
jolly-san
Cześć Jolly-san, tnx za przyjęcie mojej odpowiedzi! Dla Twojej informacji clojure.contrib.duck-streams jest teraz przestarzała. To prawdopodobnie pogłębia zamieszanie.
Michiel Borkent,
Oznacza to, że (with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))daje plony IOException Stream closedzamiast zbioru linii. Co robić? Jednak otrzymuję dobre wyniki z odpowiedzią @satyagraha.
0dB
4
Ma to związek z lenistwem. Kiedy używasz wyniku line-seq poza with-open, co ma miejsce, gdy drukujesz jego wynik do REPL, to czytnik jest już zamknięty. Rozwiązaniem jest zawijanie ciągu linii wewnątrz doall, co wymusza natychmiastową ocenę. (with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
Michiel Borkent
Dla początkujących, takich jak ja, zwróć uwagę, że doseqzwroty nilmogą prowadzić do smutnych czasów bez zwracania wartości.
października
33
Jeśli plik mieści się w pamięci, możesz go odczytać i zapisać za pomocą slurp i pluć:
(def s (slurp "filename.txt"))
(s zawiera teraz zawartość pliku jako ciąg)
(spit "newfile.txt" s)
Tworzy to newfile.txt, jeśli nie kończy pracy i zapisuje zawartość pliku. Jeśli chcesz dołączyć do pliku, możesz to zrobić
(spit "filename.txt" s :append true)
Aby czytać lub zapisywać plik liniowo, należy użyć czytnika i piszącego języka Java. Są one umieszczone w przestrzeni nazw clojure.java.io:
Zauważ, że różnica między slurp / spit a przykładami czytnika / pisarza polega na tym, że plik pozostaje otwarty (w instrukcjach let) w tym ostatnim, a odczyt i zapis jest buforowany, dzięki czemu jest bardziej wydajny, gdy wielokrotnie czyta z / zapisuje do pliku.
Dziękuję Paul. Mógłbym dowiedzieć się więcej z twoich kodów i twoich komentarzy, które są jasne w punkcie skupiającym się na odpowiedzi na moje pytanie. Dziękuję Ci bardzo.
jolly-san
Dziękuję za dodanie informacji o metodach nieco niższego poziomu, których nie podano w odpowiedzi Michiela Borkenta na temat najlepszych metod w typowych przypadkach.
Mars
@Mars Thanks. Właściwie to najpierw odpowiedziałem na to pytanie, ale odpowiedź Michiela ma większą strukturę i wydaje się być bardzo popularna.
Paul
Wykonuje dobrą robotę w zwykłych przypadkach, ale podałeś inne informacje. Dlatego dobrze, że SE pozwala na wiele odpowiedzi.
Mars
6
Odnośnie pytania 2, czasami chce się, aby strumień linii był zwracany jako obiekt pierwszej klasy. Aby uzyskać to jako leniwą sekwencję i nadal mieć plik automatycznie zamykany na EOF, użyłem tej funkcji:
Nie sądzę, że zagnieżdżanie się defnjest ideomatyczną Clojure. Twój read-next-line, o ile rozumiem, jest widoczny poza twoją read-linesfunkcją. Mogłeś (let [read-next-line (fn [] ...))zamiast tego użyć .
kristianlm
Myślę, że twoja odpowiedź byłaby nieco lepsza, gdyby zwróciła utworzoną funkcję (zamykając otwarty czytnik), a nie globalnie wiążącą.
Oddział
1
Oto jak odczytać cały plik.
Jeśli plik znajduje się w katalogu zasobów, możesz to zrobić:
Odpowiedzi:
Zakładając, że robimy tutaj tylko pliki tekstowe, a nie jakieś szalone binarne rzeczy.
Numer 1: jak wczytać cały plik do pamięci.
Niezalecane, gdy jest to naprawdę duży plik.
Numer 2: jak czytać plik wiersz po wierszu.
with-open
Makro dba, że czytelnik jest zamknięta na końcu korpusu. Funkcja czytnika przekształca ciąg (może również wykonać adres URL itp.) Do plikuBufferedReader
.line-seq
dostarcza leniwy seq. Żądanie kolejnego elementu leniwego ciągu powoduje odczytanie wiersza przez czytelnika.Zwróć uwagę, że począwszy od Clojure 1.7 możesz także używać przetworników do czytania plików tekstowych.
Numer 3: jak pisać do nowego pliku.
Ponownie, uważaj,
with-open
abyBufferedWriter
na końcu korpusu był zamknięty. Writer przekształca ciąg w ciągBufferedWriter
, którego używasz przez java interop:(.write wrtr "something").
Możesz także użyć
spit
odwrotnościslurp
:Numer 4: dołącz linię do istniejącego pliku.
To samo co powyżej, ale teraz z opcją dołączania.
Albo znowu z
spit
przeciwieństwemslurp
:PS: Aby być bardziej precyzyjnym co do faktu, że czytasz i zapisujesz do File, a nie do czegoś innego, możesz najpierw utworzyć obiekt File, a następnie przekształcić go w
BufferedReader
lub Writer:Funkcja pliku znajduje się również w clojure.java.io.
PS2: Czasami warto zobaczyć, jaki jest bieżący katalog (czyli „.”). Możesz uzyskać ścieżkę absolutną na dwa sposoby:
lub
źródło
(with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))
daje plonyIOException Stream closed
zamiast zbioru linii. Co robić? Jednak otrzymuję dobre wyniki z odpowiedzią @satyagraha.(with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
doseq
zwrotynil
mogą prowadzić do smutnych czasów bez zwracania wartości.Jeśli plik mieści się w pamięci, możesz go odczytać i zapisać za pomocą slurp i pluć:
(s zawiera teraz zawartość pliku jako ciąg)
Tworzy to newfile.txt, jeśli nie kończy pracy i zapisuje zawartość pliku. Jeśli chcesz dołączyć do pliku, możesz to zrobić
Aby czytać lub zapisywać plik liniowo, należy użyć czytnika i piszącego języka Java. Są one umieszczone w przestrzeni nazw clojure.java.io:
Zauważ, że różnica między slurp / spit a przykładami czytnika / pisarza polega na tym, że plik pozostaje otwarty (w instrukcjach let) w tym ostatnim, a odczyt i zapis jest buforowany, dzięki czemu jest bardziej wydajny, gdy wielokrotnie czyta z / zapisuje do pliku.
Tutaj jest więcej informacji: slurp spit clojure.java.io Java's BufferedReader Java's Writer
źródło
Odnośnie pytania 2, czasami chce się, aby strumień linii był zwracany jako obiekt pierwszej klasy. Aby uzyskać to jako leniwą sekwencję i nadal mieć plik automatycznie zamykany na EOF, użyłem tej funkcji:
źródło
defn
jest ideomatyczną Clojure. Twójread-next-line
, o ile rozumiem, jest widoczny poza twojąread-lines
funkcją. Mogłeś(let [read-next-line (fn [] ...))
zamiast tego użyć .Oto jak odczytać cały plik.
Jeśli plik znajduje się w katalogu zasobów, możesz to zrobić:
pamiętaj, aby wymagać / używać
clojure.java.io
.źródło
źródło
Aby odczytać plik wiersz po wierszu, nie musisz już uciekać się do interopu:
Zakłada się, że plik danych jest przechowywany w katalogu zasobów, a pierwsza linia zawiera informacje nagłówkowe, które można odrzucić.
źródło