我正在处理一个非常大的Subrip字幕文件,需要一次处理一个字幕。在Java中,要从文件中提取字幕,我会编写一个带有以下签名的方法:
Iterator<Subtitle> fromSubrip(final Iterator<String> lines);
Iterator
的使用给了我两个好处:
Subtitle
个对象的集合。由于迭代器本质上是命令式和可变的,因此它们在Clojure中可能不是惯用的。那么处理这种情况的Clojure方法是什么?
答案 0 :(得分:3)
正如弗拉基米尔所说,你需要正确处理懒惰和文件关闭。我是这样做的,如“Read a very large text file into a list in clojure”所示:
(defn lazy-file-lines
"open a (probably large) file and make it a available as a lazy seq of lines"
[filename]
(letfn [(helper [rdr]
(lazy-seq
(if-let [line (.readLine rdr)]
(cons line (helper rdr))
(do (.close rdr) nil))))]
(helper (clojure.java.io/reader filename))))
答案 1 :(得分:2)
从目录中读取所有文件,这是一种懒惰的方式。
使用go black和channel。
代码:
(ns user
(:require [clojure.core.async :as async :refer :all
:exclude [map into reduce merge partition partition-by take]]))
(defn read-dir [dir]
(let [directory (clojure.java.io/file dir)
files (filter #(.isFile %) (file-seq directory))
ch (chan)]
(go
(doseq [file files]
(with-open [rdr (clojure.java.io/reader file)]
(doseq [line (line-seq rdr)]
(>! ch line))))
(close! ch))
ch))
调用:
(def aa "D:\\Users\\input")
(let [ch (read-dir aa)]
(loop []
(when-let [line (<!! ch )]
(println line)
(recur))))
reify Iterable interace,可以在java中使用。
MyFiles.clj:
(ns user
(:gen-class :methods [#^{:static true} [readDir [String] Iterable]])
(:require [clojure.core.async :as async :refer :all
:exclude [map into reduce merge partition partition-by take]]))
(defn -readDir [dir]
(def i nil)
(let [ch (read-dir dir)
it (reify java.util.Iterator
(hasNext [this] (alter-var-root #'i (fn [_] (<!! ch))) (not (nil? i)))
(next [this] i))
itab (reify Iterable
(iterator [this] it))]
itab))
java代码:
for (Object line : MyFiles.readDir("/dir")) {
println(line)
}
答案 2 :(得分:1)
您可以使用延迟序列,例如line-seq
。
但是,您必须小心line-seq
(以及基于某些外部资源返回延迟序列的其他函数)返回的序列永远不会泄漏出来。 with-open
范围,因为在源关闭后,进一步读取延迟序列将导致异常。