A with-openmacro cuida para que o leitor esteja fechado no final do corpo. A função de leitor força uma string (também pode fazer uma URL, etc) em uma BufferedReader. line-seqoferece um seq preguiçoso. Exigir o próximo elemento do preguiçoso seq resulta em uma linha que está sendo lida pelo leitor.
Observe que, a partir do Clojure 1.7, você também pode usar transdutores para ler arquivos de texto.
Número 3: como gravar em um novo arquivo.
(use 'clojure.java.io)(with-open [wrtr (writer "/tmp/test.txt")](.write wrtr "Line to be written"))
Mais uma vez, with-opencuide para que o mesmo BufferedWriteresteja fechado no final do corpo. O Writer força uma string em a BufferedWriter, que você usa por meio da interoperabilidade java:(.write wrtr "something").
Você também pode usar spito oposto de slurp:
(spit "/tmp/test.txt""Line to be written")
Número 4: acrescente uma linha a um arquivo existente.
(use 'clojure.java.io)(with-open [wrtr (writer "/tmp/test.txt":append true)](.write wrtr "Line to be appended"))
O mesmo que acima, mas agora com a opção de acréscimo.
Ou ainda com spito oposto de slurp:
(spit "/tmp/test.txt""Line to be written":append true)
PS: Para ser mais explícito sobre o fato de você estar lendo e gravando em um arquivo e não outra coisa, você pode primeiro criar um objeto File e depois forçá-lo a um BufferedReaderou Writer:
Muito obrigado pela sua resposta detalhada. É um prazer conhecer a maneira recomendada de File IO (arquivo de texto) na versão 1.3. Parece ter havido algumas bibliotecas sobre o File IO (clojure.contrb.io, clojure.contrib.duck-streams e alguns exemplos diretamente usando o Java BufferedReader FileInputStream InputStreamReader), o que me deixou mais confusa. Além disso, há pouca informação sobre o Clojure 1.3, especialmente em japonês (minha língua natural). Obrigado.
alegre-san
Oi jolly-san, tnx por aceitar minha resposta! Para sua informação, o clojure.contrib.duck-streams agora está obsoleto. Isso possivelmente aumenta a confusão.
Michiel Borkent 14/10
Ou seja, (with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))produz em IOException Stream closedvez de uma coleção de linhas. O que fazer? Estou obtendo bons resultados com a resposta de @satyagraha, no entanto.
0dB 27/10
4
Isso tem a ver com preguiça. Quando você usa o resultado de line-seq fora do with-open, o que acontece quando você imprime o resultado no REPL, o leitor já está fechado. Uma solução é agrupar a linha-seq dentro de um doall, o que força a avaliação imediatamente. (with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
Michiel Borkent
Para os iniciantes reais como eu, observe que doseqretornos nilque podem levar a tempos tristes sem valor de retorno.
outubro
33
Se o arquivo couber na memória, você pode ler e escrever com slurp e spit:
(def s (slurp "filename.txt"))
(s agora contém o conteúdo de um arquivo como uma string)
(spit "newfile.txt" s)
Isso cria o newfile.txt se ele não sair e grava o conteúdo do arquivo. Se você deseja anexar ao arquivo, pode fazer
(spit "filename.txt" s :append true)
Para ler ou gravar um arquivo em linha, você usaria o leitor e gravador de Java. Eles estão agrupados no namespace clojure.java.io:
Observe que a diferença entre os exemplos slurp / spit e leitor / gravador é que o arquivo permanece aberto (nas instruções let) no último e a leitura e gravação são armazenadas em buffer, tornando-se mais eficiente ao ler / gravar repetidamente em um arquivo.
Obrigado Paul. Eu poderia aprender mais com seus códigos e seus comentários, que são claros no ponto em focar em responder minha pergunta. Muito obrigado.
91311 jolly-san
Obrigado por adicionar informações sobre métodos de nível ligeiramente inferior, não fornecidas na (excelente) resposta de Michiel Borkent sobre os melhores métodos para casos típicos.
Marte
@Mars Obrigado. Na verdade, eu respondi a essa pergunta primeiro, mas a resposta de Michiel tem mais estrutura e isso parece ser muito popular.
Paul
Ele faz um bom trabalho com os casos usuais, mas você forneceu outras informações. É por isso que é bom que o SE permita várias respostas.
Marte
6
Em relação à pergunta 2, às vezes se deseja que o fluxo de linhas retorne como um objeto de primeira classe. Para obter isso como uma sequência lenta, e ainda ter o arquivo fechado automaticamente no EOF, usei esta função:
Eu não acho que aninhar defné Clojure ideomatic. Seu read-next-line, pelo que entendi, é visível fora de sua read-linesfunção. Você pode ter usado um em (let [read-next-line (fn [] ...))vez disso.
precisa
Eu acho que sua resposta seria um pouco melhor se ela retornasse a função criada (fechando sobre o leitor aberto) em vez de vincular globalmente.
Ward
1
É assim que se lê o arquivo inteiro.
Se o arquivo estiver no diretório de recursos, você poderá fazer isso:
Isso pressupõe que seu arquivo de dados seja mantido no diretório de recursos e que a primeira linha seja informações de cabeçalho que podem ser descartadas.
Respostas:
Supondo que estamos apenas fazendo arquivos de texto aqui e não algumas coisas binárias loucas.
Número 1: como ler um arquivo inteiro na memória.
Não recomendado quando se trata de um arquivo muito grande.
Número 2: como ler um arquivo linha por linha.
A
with-open
macro cuida para que o leitor esteja fechado no final do corpo. A função de leitor força uma string (também pode fazer uma URL, etc) em umaBufferedReader
.line-seq
oferece um seq preguiçoso. Exigir o próximo elemento do preguiçoso seq resulta em uma linha que está sendo lida pelo leitor.Observe que, a partir do Clojure 1.7, você também pode usar transdutores para ler arquivos de texto.
Número 3: como gravar em um novo arquivo.
Mais uma vez,
with-open
cuide para que o mesmoBufferedWriter
esteja fechado no final do corpo. O Writer força uma string em aBufferedWriter
, que você usa por meio da interoperabilidade java:(.write wrtr "something").
Você também pode usar
spit
o oposto deslurp
:Número 4: acrescente uma linha a um arquivo existente.
O mesmo que acima, mas agora com a opção de acréscimo.
Ou ainda com
spit
o oposto deslurp
:PS: Para ser mais explícito sobre o fato de você estar lendo e gravando em um arquivo e não outra coisa, você pode primeiro criar um objeto File e depois forçá-lo a um
BufferedReader
ou Writer:A função de arquivo também está em clojure.java.io.
PS2: Às vezes, é útil poder ver qual é o diretório atual (então "."). Você pode obter o caminho absoluto de duas maneiras:
ou
fonte
(with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))
produz emIOException Stream closed
vez de uma coleção de linhas. O que fazer? Estou obtendo bons resultados com a resposta de @satyagraha, no entanto.(with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
doseq
retornosnil
que podem levar a tempos tristes sem valor de retorno.Se o arquivo couber na memória, você pode ler e escrever com slurp e spit:
(s agora contém o conteúdo de um arquivo como uma string)
Isso cria o newfile.txt se ele não sair e grava o conteúdo do arquivo. Se você deseja anexar ao arquivo, pode fazer
Para ler ou gravar um arquivo em linha, você usaria o leitor e gravador de Java. Eles estão agrupados no namespace clojure.java.io:
Observe que a diferença entre os exemplos slurp / spit e leitor / gravador é que o arquivo permanece aberto (nas instruções let) no último e a leitura e gravação são armazenadas em buffer, tornando-se mais eficiente ao ler / gravar repetidamente em um arquivo.
Aqui estão mais informações: slurp spit clojure.java.io BufferedReader do Java Writer de Java
fonte
Em relação à pergunta 2, às vezes se deseja que o fluxo de linhas retorne como um objeto de primeira classe. Para obter isso como uma sequência lenta, e ainda ter o arquivo fechado automaticamente no EOF, usei esta função:
fonte
defn
é Clojure ideomatic. Seuread-next-line
, pelo que entendi, é visível fora de suaread-lines
função. Você pode ter usado um em(let [read-next-line (fn [] ...))
vez disso.É assim que se lê o arquivo inteiro.
Se o arquivo estiver no diretório de recursos, você poderá fazer isso:
lembre-se de exigir / usar
clojure.java.io
.fonte
fonte
Para ler um arquivo linha por linha, você não precisa mais recorrer à interoperabilidade:
Isso pressupõe que seu arquivo de dados seja mantido no diretório de recursos e que a primeira linha seja informações de cabeçalho que podem ser descartadas.
fonte