2015-11-03 80 views
1

我在txt文件中设置了一个示例数据集。数据文件非常大,因此不能将其加载到内存中。我需要能够懒散地阅读文件。此外,我需要以随机顺序读取这些行。而且有些情况下我不需要阅读所有的文字。这是我到目前为止发现的 -Clojure懒洋洋地从文件中读取随机行

(defn read-lazy [in-file] 
     (letfn [(helper [rdr] 
          (if-let [line (.readLine rdr)] 
           (cons line (helper rdr)) 
           (do (.close rdr) nil)))] 
      (helper (io/reader in-file)))) 

它返回文件的lazy-seq。当我需要时,如何在lazy-seq中随机循环循环?我认为使用go block可以在这里帮助。去块可以在通道中放置一条随机线,等待某些东西消耗掉它。一旦数据被读取,它会在通道中放入另一条线等待下一次读取。我怎样才能实现呢?

以下是我已经工作了(不是随机的) -

(def lazy-ch (chan)) 
(defn async-fetch-set [in-file] 
    (go 
     (with-open [reader (io/reader in-file)] 
      (doseq [line (line-seq reader)] 
       (>! lazy-ch line))) 
     (close! lazy-ch))) 

(println "got: " (<!! lazy-ch)) 

这是解决这个问题的好办法?有更好的解决方案吗?我可能不需要阅读所有内容,所以我希望能够在需要时关闭阅读器。

+0

所以,以确保我正确地理解你的问题:你需要在序列中的文件的每一行执行相同的操作,但该序列顺序的问题随机? –

+0

是。这就是我想要做的。我添加了更新 – Lordking

回答

1

上面的解决方案不包含任何随机性。 Go频道是先进先出的结构。如果您确实需要随机读取,则首先需要对文件中的行数进行计数,然后使用(rand N)在区间[0..N-1]中生成一个整数I,然后从文件中读取行I

有几种不同的方法可以从文件中读取I行,这会影响速度与内存的要求。

1
(defn char-seq 
    "Returns a lazy sequence of characters from rdr. rdr must implement 
    java.io.Reader." 
    [rdr] 
    (let [c (.read rdr)] 
    (if-not (neg? c) 
     (cons (char c) (lazy-seq (char-seq rdr)))))) 

(defn line-offsets 
    "Returns a lazy sequence of offsets of all lines in s." 
    [s] 
    (if (seq s) 
    (->> (partition-all 3 1 s) 
     (map-indexed 
      (fn [i [a b c]] 
      (cond 
       (= b \newline) (if c (+ 2 i)) 
       (= a \return) (if b (inc i))))) 
     (filter identity) 
     (cons 0)))) 

(defn ordered-line-seq 
    "Returns the lines of text from raf at each offset in offsets as a lazy 
    sequence of strings. raf must implement java.io.RandomAccessFile." 
    [raf offsets] 
    (map (fn [i] 
     (.seek raf i) 
     (.readLine raf)) 
     offsets)) 

用法示例:

(let [filename "data.txt" 
     offsets (with-open [rdr (clojure.java.io/reader filename)] 
       (shuffle (line-offsets (char-seq rdr))))] 
    (with-open [raf (java.io.RandomAccessFile. filename "r")] 
    (dorun (map println (ordered-line-seq raf offsets)))))