क्लोजर 1.3 में, फ़ाइल को कैसे पढ़ें और लिखें


163

मैं क्लोजर 1.3 में एक फाइल को पढ़ने और लिखने के "अनुशंसित" तरीके को जानना चाहता हूं।

  1. पूरी फाइल को कैसे पढ़ें
  2. फ़ाइल लाइन को लाइन से कैसे पढ़ें
  3. नई फाइल कैसे लिखें
  4. किसी मौजूदा फ़ाइल में एक पंक्ति कैसे जोड़ें

2
Google से पहला परिणाम: lethain.com/reading-file-in-clojure
jcubic

8
यह परिणाम 2009 से है, कुछ चीजों को हाल ही में बदल दिया गया है।
सर्गेई

11
वास्तव में। यह StackOverflow प्रश्न अब Google पर पहला परिणाम है।
mydoghasworms

जवाबों:


273

यह मानते हुए कि हम केवल पाठ फ़ाइलें यहाँ कर रहे हैं और कुछ पागल बाइनरी सामान नहीं।

नंबर 1: मेमोरी में पूरी फाइल कैसे पढ़ें।

(slurp "/tmp/test.txt")

अनुशंसित नहीं जब यह वास्तव में बड़ी फ़ाइल है।

नंबर 2: फाइल लाइन को लाइन से कैसे पढ़ें।

(use 'clojure.java.io)
(with-open [rdr (reader "/tmp/test.txt")]
  (doseq [line (line-seq rdr)]
    (println line)))

with-openमैक्रो ख्याल रखता है कि पाठक शरीर के अंत में बंद कर दिया है। रीडर फ़ंक्शन एक स्ट्रिंग (यह एक URL आदि भी कर सकता है) को एक में समेटता है BufferedReaderline-seqएक आलसी seq बचाता है। आलसी seq के अगले तत्व की मांग करने से पाठक से पढ़ी जाने वाली एक पंक्ति में परिणाम होता है।

ध्यान दें कि क्लोजर 1.7 से आगे, आप पाठ फ़ाइलों को पढ़ने के लिए ट्रांसड्यूसर का भी उपयोग कर सकते हैं ।

नंबर 3: नई फाइल में कैसे लिखें।

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt")]
  (.write wrtr "Line to be written"))

फिर, with-openध्यान रखता है कि BufferedWriterशरीर के अंत में बंद हो। लेखक एक स्ट्रिंग को एक में जोड़ता है BufferedWriter, जिसे आप जावा इंटरॉप के माध्यम से उपयोग करते हैं:(.write wrtr "something").

आप इसका उपयोग भी कर सकते हैं spit, इसके विपरीत slurp:

(spit "/tmp/test.txt" "Line to be written")

नंबर 4: एक मौजूदा फाइल के लिए एक लाइन संलग्न।

(use 'clojure.java.io)
(with-open [wrtr (writer "/tmp/test.txt" :append true)]
  (.write wrtr "Line to be appended"))

ऊपर के समान, लेकिन अब एपेंड विकल्प के साथ।

या फिर spit, इसके विपरीत slurp:

(spit "/tmp/test.txt" "Line to be written" :append true)

पुनश्च: इस तथ्य के बारे में अधिक स्पष्ट होने के लिए कि आप एक फ़ाइल में पढ़ रहे हैं और लिख रहे हैं, और कुछ और नहीं, आप पहले एक फ़ाइल ऑब्जेक्ट बना सकते हैं और फिर इसे एक BufferedReaderराइटर में जमा कर सकते हैं:

(reader (file "/tmp/test.txt"))
;; or
(writer (file "tmp/test.txt"))

फ़ाइल फ़ंक्शन clojure.java.io में भी है।

PS2: कभी-कभी यह देखना आसान होता है कि वर्तमान निर्देशिका क्या है (इसलिए "")। आप दो तरीकों से संपूर्ण मार्ग प्राप्त कर सकते हैं:

(System/getProperty "user.dir") 

या

(-> (java.io.File. ".") .getAbsolutePath)

1
आपके विस्तृत उत्तर के लिए बहुत बहुत धन्यवाद। मुझे 1.3 में फ़ाइल IO (पाठ फ़ाइल) के अनुशंसित तरीके को जानकर खुशी हुई। ऐसा लगता है कि फ़ाइल IO (clojure.contrb.io, clojure.contrib.duck-streams और कुछ उदाहरण सीधे Java BufferedReader FileInputStream InputStreamRderder) का उपयोग करते हुए कुछ पुस्तकालयों के बारे में है, जिसने मुझे और अधिक भ्रमित कर दिया है। इसके अलावा क्लोजर 1.3 के बारे में विशेष रूप से जापानी (मेरी प्राकृतिक भाषा) में बहुत कम जानकारी है धन्यवाद।
जॉली-सान

हाय जॉली-सान, मेरे जवाब को स्वीकार करने के लिए tnx! आपकी जानकारी के लिए, अब clojure.contrib.duck-st स्ट्रीम को हटा दिया गया है। यह संभवतः भ्रम में जोड़ता है।
मिसेल बोर्केंट

यही है, लाइनों के संग्रह के बजाय (with-open [rdr (reader "/tmp/test.txt")] (line-seq rdr))पैदावार IOException Stream closed। क्या करें? हालांकि @satyagraha द्वारा जवाब के साथ अच्छे परिणाम मिल रहे हैं।
0dB

4
यह आलस्य के साथ करना है। जब आप आउट-ओपन के बाहर लाइन-सीक के परिणाम का उपयोग करते हैं, जो तब होता है जब आप इसका परिणाम आरईपीएल को प्रिंट करते हैं, तो पाठक पहले से ही बंद हो जाता है। एक समाधान एक डॉल के अंदर लाइन-सीक को लपेटने के लिए है, जो मूल्यांकन को तुरंत मजबूर करता है। (with-open [rdr (reader "/tmp/test.txt")] (doall (line-seq rdr)))
मिसेल बोर्केंट

मेरे रूप में वास्तविक शुरुआती के लिए, ध्यान दें कि doseqरिटर्न nilजो दु: ख-वापसी-मूल्य समय की ओर ले जा सकता है।
21

33

यदि फ़ाइल मेमोरी में फिट हो जाती है, तो आप इसे स्लरप और थूक के साथ पढ़ और लिख सकते हैं:

(def s (slurp "filename.txt"))

(अब एक स्ट्रिंग के रूप में एक फ़ाइल की सामग्री शामिल है)

(spit "newfile.txt" s)

यदि यह बाहर नहीं निकलता है और फ़ाइल सामग्री लिखता है तो यह newfile.txt बनाता है। यदि आप उस फ़ाइल को अपेंड करना चाहते हैं जो आप कर सकते हैं

(spit "filename.txt" s :append true)

एक फ़ाइल को पढ़ने या लिखने के लिए आप जावा के पाठक और लेखक का उपयोग करेंगे। वे नाम स्थान में लिपटे हैं clojure.java.io:

(ns file.test
  (:require [clojure.java.io :as io]))

(let [wrtr (io/writer "test.txt")]
  (.write wrtr "hello, world!\n")
  (.close wrtr))

(let [wrtr (io/writer "test.txt" :append true)]
  (.write wrtr "hello again!")
  (.close wrtr))

(let [rdr (io/reader "test.txt")]
  (println (.readLine rdr))
  (println (.readLine rdr)))
; "hello, world!"
; "hello again!"

ध्यान दें कि स्लप / थूक और पाठक / लेखक के उदाहरणों के बीच अंतर यह है कि फ़ाइल बाद में खुली रहती है (लेट स्टेटमेंट में) और पढ़ना और लिखना बफ़र किया जाता है, इस प्रकार फ़ाइल से बार-बार पढ़ने / लिखने पर अधिक कुशल होता है।

यहाँ अधिक जानकारी है: slurp थूक clojure.java.io जावा के बफ़ररेडर जावा के लेखक


1
धन्यवाद पॉल। मैं आपके कोड और आपकी टिप्पणियों से अधिक सीख सकता हूं जो मेरे प्रश्न का उत्तर देने पर ध्यान केंद्रित करने में स्पष्ट हैं। आपका बहुत बहुत धन्यवाद।
जॉली-सान

विशिष्ट मामलों के लिए सर्वोत्तम तरीकों पर मिचेल बोर्केंट (उत्कृष्ट) के जवाब में नहीं दी गई थोड़ा निचले स्तर के तरीकों पर जानकारी जोड़ने के लिए धन्यवाद।
मंगल

@Mars धन्यवाद वास्तव में मैंने पहले इस प्रश्न का उत्तर दिया था, लेकिन मिचेल के उत्तर में अधिक संरचना है और यह बहुत लोकप्रिय प्रतीत होता है।
पॉल

वह सामान्य मामलों के साथ एक अच्छा काम करता है, लेकिन आपने अन्य जानकारी प्रदान की है। इसलिए यह अच्छा है कि एसई कई उत्तरों की अनुमति देता है।
मंगल

6

प्रश्न 2 के बारे में, कभी-कभी यह चाहता है कि लाइनों की धारा प्रथम श्रेणी की वस्तु के रूप में वापस आए। इसे एक आलसी अनुक्रम के रूप में प्राप्त करने के लिए, और अभी भी फ़ाइल ईओएफ पर स्वचालित रूप से बंद है, मैंने इस फ़ंक्शन का उपयोग किया है:

(use 'clojure.java.io)

(defn read-lines [filename]
  (let [rdr (reader filename)]
    (defn read-next-line []
      (if-let [line (.readLine rdr)]
       (cons line (lazy-seq (read-next-line)))
       (.close rdr)))
    (lazy-seq (read-next-line)))
)

(defn echo-file []
  (doseq [line (read-lines "myfile.txt")]
    (println line)))

7
मुझे नहीं लगता कि नेस्टिंग defnआइडोमैटिक क्लोजर है। आपका read-next-line, जहाँ तक मैं समझता हूँ, आपके read-linesकार्य के बाहर दिखाई दे रहा है । आप एक (let [read-next-line (fn [] ...))बजाय इस्तेमाल किया हो सकता है ।
क्रिस्तिअल्म

मुझे लगता है कि आपका जवाब थोड़ा बेहतर होगा अगर यह विश्व स्तर पर बाध्यकारी के बजाय (खुले पाठक पर बंद) बनाए गए फ़ंक्शन को लौटाए।
वार्ड

1

इस तरह से पूरी फाइल को पढ़ना है।

यदि फ़ाइल संसाधन निर्देशिका में है, तो आप यह कर सकते हैं:

(let [file-content-str (slurp (clojure.java.io/resource "public/myfile.txt")])

आवश्यकता / उपयोग करना याद रखें clojure.java.io



0

फ़ाइल लाइन को लाइन से पढ़ने के लिए आपको अब इंटरोप का सहारा लेने की आवश्यकता नहीं है:

(->> "data.csv"
      io/resource
      io/reader
      line-seq
      (drop 1))

यह मानता है कि आपकी डेटा फ़ाइल संसाधन निर्देशिका में रखी गई है और पहली पंक्ति हेडर की जानकारी है जिसे खारिज किया जा सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.