<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    Clojure世界:文件IO

    Posted on 2012-02-16 22:38 dennis 閱讀(7096) 評論(3)  編輯  收藏 所屬分類: Clojure
        文件讀寫是日常編程中最經常使用的操作之一。這篇blog將大概介紹下Clojure里對文件操作的常用類庫。

        首先介紹標準庫clojure.java.io,這是最經常用的IO庫,定義了常見的IO操作。

        首先,直接看一個例子,可以熟悉下大多數常用的函數:
    (ns io
      (:use [clojure.java.io]))

    ;;file函數,獲取一個java.io.File對象
    (
    def f (file "a.txt"))

    ;;拷貝文件使用copy
    (copy f (file 
    "b.txt"))

    ;;刪除文件,使用delete
    -file
    (delete
    -file f)

    ;;更經常使用reader和writer
    (
    def rdr (reader "b.txt" :encoding "utf-8"))
    (
    def wtr (writer "c.txt" :append true))

    ;;copy可以接受多種類型的參數
    (copy rdr wtr :buffer
    -size 4096)

    ;;關閉文件
    (.close wtr)
    (.close rdr)



        這個例子基本上說明了大多數常見的操作。但是有些問題需要解釋下。

        首先,通過file這個函數可以將各種類型的對象轉化為java.io.File對象,file可以接受String,URL,URI以及java.io.File本身作為參數,并返回java.io.File。有了File對象,你就可以調用java.io.File類中的各種方法,比如判斷文件是否存在:
    (.exists (file "a.txt")) => true or false

        其次,可以通過delete-file來刪除一個文件,它是調用File的delete方法來執行的,但是File.delete會返回一個布爾值告訴你成功還是失敗,如果返回false,那么delete-file會拋出IO異常,如果你不想被這個異常打擾,可以讓它“保持安靜”:
        (delete-file f true)

        拷貝文件很簡單,使用copy搞定,copy也可以很“寬容”,也可以接受多種類型的參數并幫你自動轉換,input可以是InputStream, Reader, File, byte[] 或者String,而output可以是OutputStream, Writer或者File。是不是很給力?這都是通過Clojure的protocol和defmulti做到的。但是,copy并不幫你處理文件的關閉問題,假設你傳入的input是一個File,output也是一個File,copy會自動幫你打開InputStream和OutputStream并建立緩沖區做拷貝,但是它不會幫你關閉這兩個流,因此你要小心,如果你經常使用copy,這可能是個內存泄漏的隱患。

        更常用的,我們一般都是用reader和writer函數來打開一個BufferedReader和BufferedWriter做讀寫,同樣reader和writer也可以接受多種多樣的參數類型,甚至包括Socket也可以。因為writer打開的通常是一個BufferedWriter,所以你如果用它寫文件,有時候發現write之后文件還是沒有內容,這是因為數據暫時寫到了緩沖區里,沒有刷入到磁盤,可以明確地調用(.flush wtr)來強制寫入;或者在wtr關閉后系統幫你寫入。reader和writer還可以傳入一些配置項,如:encoding指定讀寫的字符串編碼,writer可以指定是否為append模式等。

        Clojure并沒有提供關閉文件的函數或者宏,你簡單地調用close方法即可。clojure.java.io的設計很有原則,它不準備將java.io都封裝一遍,而是提供一些最常用方法的簡便wrapper供你使用。

        剛才提到copy不會幫你關閉打開的文件流,但是我們可以利用with-open這個宏來自動幫你管理打開的流:
    (with-open [rdr (reader "b.txt")
                wtr (writer 
    "c.txt")]
      (copy rdr wtr))

       with-open宏會自動幫你關閉在binding vector里打開的流,你不再需要自己調用close,也不用擔心不小心造成內存泄漏。因此我會推薦你盡量用reader和writer結合with-open來做文件操作,而不要使用file函數。file函數應該用在一些判斷是否存在,判斷文件是否為目錄等操作上。

        在clojure.core里,還有兩個最常用的函數slurp和spit,一個吃,一個吐,也就是slurp讀文件,而spit寫文件,他們類似Ruby的File里的read和write,用來完整地讀或者寫文件:
        (prn (slurp "c.txt"))
        (spit "c.txt" "hello world")

       用法簡單明了,slurp將文件完整地讀出并返回字符串作為結果,它還接受:encoding參數來指定字符串編碼,你猜的沒錯,它就是用reader和with-open實現的。spit同樣很簡單,將content轉化為字符串寫入文件,也接受:encoding和:append參數。

        深度優先遍歷目錄,可以使用file-seq,返回一個深度優先順序遍歷的目錄列表,這是一個LazySeq:
    (user=> (file-seq (java.io.File. "."))


    (
    #<File .> #<File ./.gitignore> #<File ./.lein-deps-sum> #<File ./b.txt> #<File ./c.txt> #<File ./classes> ⋯⋯ )

        上面的介紹已經足以讓你對付大多數需求了。接下來,介紹下幾個開源庫。首先是fs這個庫,它封裝了java.io.File類的大多數方法,讓你用起來很clojure way,很舒服,例如:
    (exists? "a.txt")
    (directory? 
    "file")
    (file? 
    "file")
    (name 
    "/home/dennis/.inputrc")
    (mkdir 
    "/var/data")
    (rename 
    "a.txt" "b.txt")
    (
    def tmp (temp-dir))
    (glob 
    #".*test.*")
    (chmod 744 "a.txt")

    ⋯⋯

        更多介紹請看它的源碼。讀寫二進制文件也是一個很常見的需求,Clojure有幾個DSL庫干這個事情,可以很直觀地定義二進制格式來encode/decode,比如byte-spec這個庫,看看它的例子:
    defspec basic-spec
             :a :int8
             :b :int16
             :c :int32
             :d :float32
             :e :float64
             :f :string)

    ;; An object to serialize
    (
    def foo {:a 10 :b 20 :c 40 :d 23.2 :e 23.2 :f "asddf"})

    ;; And serialize it to a byte array like this:
    (spec
    -write-bytes basic-spec foo) ;; => [bytes]

    ;; reading 
    in a byte array with the basic-spec format works like this:
    (spec
    -read-bytes basic-spec bytes)
        相當直觀和給力吧。Gloss是一個更強大的DSL庫,非常適合做網絡通訊的協議處理。這里就不多做介紹了,你可以自己看它的例子和文檔。
       
        轉載請注明出處:http://www.tkk7.com/killme2008/archive/2012/02/16/370144.html
       

    評論

    # re: Clojure世界:文件IO  回復  更多評論   

    2012-02-17 09:40 by tb
    很強大啊

    # re: Clojure世界:文件IO  回復  更多評論   

    2013-07-05 01:13 by pimgeek
    感謝分享, 關于 slurp 和 spit 的文件讀寫操作例子, 對我非常有幫助!

    # re: Clojure世界:文件IO  回復  更多評論   

    2014-05-27 11:42 by markxueyuan
    感覺這是中文世界介紹clojure最強的博客了!
    主站蜘蛛池模板: 久青草视频在线观看免费| 97在线视频免费公开观看| 日韩午夜免费视频| 亚洲一区二区三区免费| 亚洲美女自拍视频| 在免费jizzjizz在线播| 国产成人精品亚洲精品| 一道本不卡免费视频| 亚洲中文字幕无码一区| 久久国产亚洲精品| 免费网站看v片在线香蕉| 亚洲AV日韩AV天堂一区二区三区| 精品亚洲国产成人av| 24小时日本韩国高清免费| 亚洲色欲色欲综合网站| 亚洲日韩在线观看免费视频| 亚洲国产精品人人做人人爱| selaoban在线视频免费精品| 亚洲精品二区国产综合野狼| 8090在线观看免费观看| 亚洲中文字幕AV每天更新| 8x成人永久免费视频| 33333在线亚洲| 亚洲av区一区二区三| 国产精品亚洲精品久久精品| 亚洲精品和日本精品| 99精品视频免费在线观看| 亚洲一级特黄特黄的大片| 国产免费131美女视频| 91免费福利视频| 2017亚洲男人天堂一| 亚洲精品视频免费观看| 99在线观看精品免费99| 亚洲依依成人亚洲社区| 国内精品99亚洲免费高清| 国产精品成人免费福利| 一级毛片免费在线播放| 亚洲国产成人va在线观看网址| 亚洲成A∨人片天堂网无码| 99久久99热精品免费观看国产| 国产在亚洲线视频观看|