<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 閱讀(7118) 評論(3)  編輯  收藏 所屬分類: Clojure
        文件讀寫是日常編程中最經(jīng)常使用的操作之一。這篇blog將大概介紹下Clojure里對文件操作的常用類庫。

        首先介紹標(biāo)準(zhǔn)庫clojure.java.io,這是最經(jīng)常用的IO庫,定義了常見的IO操作。

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

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

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

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

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

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

    ;;關(guān)閉文件
    (.close wtr)
    (.close rdr)



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

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

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

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

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

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

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

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

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

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

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


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

        上面的介紹已經(jīng)足以讓你對付大多數(shù)需求了。接下來,介紹下幾個開源庫。首先是fs這個庫,它封裝了java.io.File類的大多數(shù)方法,讓你用起來很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")

    ⋯⋯

        更多介紹請看它的源碼。讀寫二進(jìn)制文件也是一個很常見的需求,Clojure有幾個DSL庫干這個事情,可以很直觀地定義二進(jìn)制格式來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)
        相當(dāng)直觀和給力吧。Gloss是一個更強(qiáng)大的DSL庫,非常適合做網(wǎng)絡(luò)通訊的協(xié)議處理。這里就不多做介紹了,你可以自己看它的例子和文檔。
       
        轉(zhuǎn)載請注明出處:http://www.tkk7.com/killme2008/archive/2012/02/16/370144.html
       

    評論

    # re: Clojure世界:文件IO  回復(fù)  更多評論   

    2012-02-17 09:40 by tb
    很強(qiáng)大啊

    # re: Clojure世界:文件IO  回復(fù)  更多評論   

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

    # re: Clojure世界:文件IO  回復(fù)  更多評論   

    2014-05-27 11:42 by markxueyuan
    感覺這是中文世界介紹clojure最強(qiáng)的博客了!
    主站蜘蛛池模板: 亚洲一区二区三区深夜天堂| 真实乱视频国产免费观看| heyzo亚洲精品日韩| 亚洲精品又粗又大又爽A片| 国产h肉在线视频免费观看| 国产免费怕怕免费视频观看| 亚洲av无码不卡久久| 国产精品免费网站| 日美韩电影免费看| 亚洲精品无码专区在线| 日本不卡高清中文字幕免费| MM1313亚洲精品无码久久| 四虎永久在线精品免费观看地址| 亚洲国产欧美国产综合一区| 超pen个人视频国产免费观看| 国产青草视频在线观看免费影院| 国产成人免费网站| 99在线精品免费视频九九视| 黄在线观看www免费看| 中文字幕av免费专区| 免费无码又爽又刺激聊天APP| 免费无码一区二区三区| 情人伊人久久综合亚洲| 最近国语视频在线观看免费播放| 亚洲韩国精品无码一区二区三区| 久久久精品午夜免费不卡| 成人性生交视频免费观看| 久久亚洲精品成人无码| 亚洲国产成人VA在线观看| 久久久久久久99精品免费观看| 亚洲欧洲日产国码www| 国产小视频在线观看免费| 中国一级特黄的片子免费 | 亚洲AV无码一区二区三区久久精品 | 久久九九AV免费精品| 亚洲精品色婷婷在线影院| 久久精品国产这里是免费| 香蕉大伊亚洲人在线观看| 中文国产成人精品久久亚洲精品AⅤ无码精品 | 色噜噜综合亚洲av中文无码| www免费黄色网|