Проблема в том, что with-open
вызывает .close
, когда программа выходит из области действия, к которой она относится, но все строки не обязательно были прочитаны к этому моменту.
Мое решение, вероятно, является оскорбительной мерзостью,никогда бы не увидел дневного света, но вот идея: создайте "lazy-seq
", который просто вызывает .close
, и объедините его в конец списка line-seq
:
(defn lazy-lines [^File file]
(let [rdr (io/reader file)]
(lazy-cat (line-seq rdr)
(do (.close rdr)
nil)))) ; Explicit nil to indicate termination
(defn get-lines [^String path]
(->> path
(File.)
(file-seq)
(filter #(-> ^File % (.getAbsolutePath) (clojure.string/includes? ".json")))
(mapcat lazy-lines)))
Из моего быстрого тестирования с файлами на моем рабочем столе, похоже, работает.Если вы добавляете println
в завершающий lazy-seq
, он печатается, как и ожидалось, поэтому файл закрывается .
Я не решаюсь предложить это решение, так как оно полагаетсяна проведение побочных эффектов внутри ленивого списка, который я был вынужден «чувствовать неправильно» по понятным причинам.Основным недостатком этого метода является то, что файл не будет закрыт, пока не будет проанализирована вся последовательность, и файл будет оставаться открытым все время, пока не будет достигнут конец.Однако, учитывая ограничения, я не понимаю, как можно было бы избежать любой из этих проблем.
Я понял, что использовал lazy-cat
немного неправильно.У меня была лишняя ненужная lazy-seq
оболочка.Это сейчас исправлено.Вы также можете просто использовать что-то вроде
(apply concat (line-seq rdr)
(lazy-seq (do (.close rdr)
nil))))))
вместо lazy-cat
.