स्कैला में पूरी फाइल पढ़ें?


312

स्कैला में एक पूरी फ़ाइल को मेमोरी में पढ़ने का एक सरल और विहित तरीका क्या है? (आदर्श रूप से, वर्ण एन्कोडिंग पर नियंत्रण के साथ।)

सबसे अच्छा मैं आ सकता है:

scala.io.Source.fromPath("file.txt").getLines.reduceLeft(_+_)

या मैं जावा के ईश्वर-भयानक मुहावरों में से एक का उपयोग करने वाला हूं , जिनमें से सबसे अच्छा है (बाहरी पुस्तकालय का उपयोग किए बिना):

import java.util.Scanner
import java.io.File
new Scanner(new File("file.txt")).useDelimiter("\\Z").next()

मेलिंग लिस्ट चर्चाओं को पढ़ने से, मेरे लिए यह स्पष्ट नहीं है कि scala.io.Source यहां तक ​​कि विहित I / O पुस्तकालय भी माना जाता है। मुझे समझ में नहीं आता कि इसका अभीष्ट उद्देश्य क्या है।

... मैं कुछ मृत-सरल और याद रखना आसान चाहूंगा। उदाहरण के लिए, इन भाषाओं में मुहावरे को भूलना बहुत कठिन है ...

Ruby    open("file.txt").read
Ruby    File.read("file.txt")
Python  open("file.txt").read()

12
यदि आप सही उपकरण जानते हैं तो जावा बुरा नहीं है। आयात org.apache.commons.io.FileUtils; FileUtils.readFileToString (नई फ़ाइल ("file.txt", "UTF-8")
smartnut007

25
यह टिप्पणी भाषा डिजाइन के बिंदु को याद करती है। कोई भी भाषा, जो आपके द्वारा किए जाने वाले ऑपरेशन के लिए एक साधारण लाइब्रेरी फ़ंक्शन उपलब्ध है, इसलिए इसका फ़ंक्शन इन्वोकेशन सिंटैक्स जितना अच्छा है। एक अनंत और 100% याद की गई लाइब्रेरी को देखते हुए, सभी कार्यक्रमों को एक ही फ़ंक्शन कॉल के साथ लागू किया जाएगा। एक प्रोग्रामिंग भाषा अच्छी होती है जब उसे किसी विशिष्ट परिणाम को प्राप्त करने के लिए पहले से मौजूद कम-फैब घटकों की आवश्यकता होती है।
क्रिस माउंटफोर्ड

जवाबों:


429
val lines = scala.io.Source.fromFile("file.txt").mkString

वैसे, " scala." वास्तव में आवश्यक नहीं है, क्योंकि यह हमेशा वैसे भी दायरे में है, और आप निश्चित रूप से, io की सामग्री को पूरी तरह या आंशिक रूप से आयात कर सकते हैं, और "io" को पूर्व निर्धारित करने से बचें। भी।

हालाँकि, उपरोक्त फ़ाइल को खुला छोड़ देता है। समस्याओं से बचने के लिए, आपको इसे इस तरह से बंद करना चाहिए:

val source = scala.io.Source.fromFile("file.txt")
val lines = try source.mkString finally source.close()

उपरोक्त कोड के साथ एक और समस्या यह है कि इसके कार्यान्वयन की प्रकृति के कारण यह भयानक धीमी है। बड़ी फ़ाइलों के लिए एक का उपयोग करना चाहिए:

source.getLines mkString "\n"

48
मुझे पार्टी में बहुत देर हो चुकी है, लेकिन मुझे लोगों से नफरत है कि वे यह नहीं जान पाएंगे कि वे "io.File (" / etc / passwd ") कर सकते हैं। गालियों में"।
पीपी

28
@extempore यदि आप वास्तव में सोचते हैं कि मैं आभारी हूं, तो मुझे वास्तव में खेद है। मैं स्केला भाषा के आपके समर्थन की गहराई से सराहना करता हूं और हर बार जब आपने व्यक्तिगत रूप से एक मुद्दे को देखा था, तो मैंने एक समस्या का हल सुझाया, जो मेरे पास था, या मुझे कुछ समझाया। फिर, मैं मौका लेता हूँ, तब आपको scala.io को कुछ सभ्य और योग्य बनाने के लिए धन्यवाद देने के लिए। मैं अब से मेरे धन्यवाद में और अधिक मुखर रहूंगा, लेकिन मुझे अभी भी नाम से नफरत है, क्षमा करें।
डेनियल सी। सोबरल

49
"स्लरप" कई वर्षों से पर्ल में एक बार में एक पूरी फ़ाइल पढ़ने का नाम है। पर्ल के पास भाषाओं के सी परिवार की तुलना में अधिक आंत और अनौपचारिक नामकरण परंपरा है, जो कुछ अरुचिकर लग सकता है, लेकिन इस मामले में मुझे लगता है कि यह फिट बैठता है: यह एक बदसूरत अभ्यास के लिए एक बदसूरत शब्द है। जब आप थप्पड़ मारते हैं (), तो आप जानते हैं कि आप कुछ शरारती कर रहे हैं क्योंकि आपको सिर्फ यह लिखना था।
मार्कस डाउनिंग

15
File.read () एक अच्छा नाम होगा, और इसके अलावा रूबी और पायथन के साथ संगत होगा।
ब्रेंडन OConnor

26
@ कस्टमर: आप लोगों को घृणित होने से नहीं रोक सकते। यह सिर्फ तरीका है। यह आपको परेशान नहीं करना चाहिए कि कुछ लोगों को आपकी पसंद की हर पसंद पसंद नहीं है। यह सिर्फ जीवन है, आप हर किसी को खुश नहीं कर सकते :)
एलेक्स बारानोस्की

58

बस डैनियल के समाधान पर विस्तार करने के लिए, आप किसी भी फ़ाइल में निम्नलिखित आयात सम्मिलित करके जबरदस्त तरीके से चीजों को छोटा कर सकते हैं जिसमें फ़ाइल हेरफेर की आवश्यकता होती है:

import scala.io.Source._

इसके साथ, आप अब कर सकते हैं:

val lines = fromFile("file.txt").getLines

मैं एक एकल में एक पूरी फ़ाइल पढ़ने से सावधान रहना होगा String। यह एक बहुत ही बुरी आदत है, जो आपको जितनी जल्दी समझेगी उतनी ही जल्दी और मुश्किल से काटेगी। getLinesविधि प्रकार का एक मान देता हैIterator[String] । यह प्रभावी रूप से फ़ाइल में एक आलसी कर्सर है, जो आपको मेमोरी ग्लूट को जोखिम में डाले बिना सिर्फ डेटा की जांच करने की अनुमति देता है।

ओह, और आपके निहित प्रश्न का उत्तर देने के लिए Source : हाँ, यह विहित I / O पुस्तकालय है। अधिकांश कोड java.ioअपने निचले स्तर के इंटरफेस और मौजूदा चौखटे के साथ बेहतर संगतता के कारण उपयोग करना समाप्त करते हैं , लेकिन किसी भी कोड का उपयोग करने के लिए एक विकल्प होना चाहिए Source, विशेष रूप से सरल फ़ाइल हेरफेर के लिए।


ठीक। मेरे स्रोत की नकारात्मक धारणा के लिए एक कहानी है: मैं एक बार अब की तुलना में एक अलग स्थिति में था, जहां मेरे पास एक बहुत बड़ी फाइल थी जो स्मृति में फिट नहीं होगी। स्रोत का उपयोग करने से प्रोग्राम क्रैश हो गया; यह पता चला कि यह एक ही बार में पूरी बात पढ़ने की कोशिश कर रहा था।
ब्रेंडन OConnor

7
स्रोत को पूरी फ़ाइल को मेमोरी में पढ़ने के लिए नहीं माना जाता है। यदि आप गेटलाइन के बाद, या किसी अन्य तरीके से एक संग्रह का उत्पादन करेंगे, तो आप मेमोरी में सब कुछ प्राप्त करते हैं। अब, सोर्स एक हैक है , जिसका उद्देश्य नौकरी करना है, न कि एक सावधानीपूर्वक सोची-समझी लाइब्रेरी। यह स्केल 2.8 में सुधार किया जाएगा, लेकिन निश्चित रूप से स्काला समुदाय के लिए एक अच्छा I / O API को परिभाषित करने में सक्रिय होने का अवसर है।
डैनियल सी। सोबरल

36
// for file with utf-8 encoding
val lines = scala.io.Source.fromFile("file.txt", "utf-8").getLines.mkString

6
मूल उत्तर के लिए "getLines" जोड़ने से सभी नए अंक निकल जाएंगे। "Source.fromFile (" file.txt "," utf-8 ") होना चाहिए। mkString"।
२३

9
डैनियल सी। सोबरल के उत्तर में मेरी टिप्पणी भी देखें - यह उपयोग स्रोत के उदाहरण को बंद नहीं करेगा, इसलिए स्काला फ़ाइल पर लॉक को बनाए रख सकता है।
djb

26

(EDIT: यह scala 2.9 में काम नहीं करता है और शायद 2.8 या तो नहीं)

ट्रंक का उपयोग करें:

scala> io.File("/etc/passwd").slurp
res0: String = 
##
# User Database
# 
... etc

14
" slurp"? क्या हमने वास्तव में स्पष्ट, सहज नाम को खाई है? इसके साथ समस्या slurpयह है कि यह पहली भाषा के रूप में अंग्रेजी के साथ किसी को, कम से कम, के बाद समझ में आ सकता है, लेकिन आप इसे शुरू करने के बारे में कभी नहीं सोचेंगे!
डैनियल सी। सोबरल

5
बस इस सवाल / जवाब पर अड़ गया। File2.8.0 में नहीं रह गया है, है ना?
हुहुंजल

4
थपकी बहुत अच्छी लगती है। :) मुझे इसकी उम्मीद नहीं थी, लेकिन मुझे उम्मीद नहीं थी कि स्क्रीन पर आउटपुट का नाम 'प्रिंट' होगा। slurpशानदार है! :) शानदार था? मुझे नहीं मिला। ;
उपयोगकर्ता अज्ञात 4

5
scala-2.10.0 में पैकेज का नाम scala.reflect.io.File है और इस "फाइल" के बारे में एक प्रश्न है। extempore, इस फ़ाइल को "प्रयोगात्मक" के रूप में चिह्नित क्यों किया गया है? क्या ये सुरक्षित है? क्या यह फाइल सिस्टम के लिए लॉक फ्री है?
VasiliNovikov

4
स्लरप का इस उद्देश्य के लिए एक लंबा इतिहास रहा है, मुझे लगता है, perl से
क्रिस माउंटफोर्ड

18
import java.nio.charset.StandardCharsets._
import java.nio.file.{Files, Paths}

new String(Files.readAllBytes(Paths.get("file.txt")), UTF_8)

वर्ण एन्कोडिंग पर नियंत्रण, और सफाई के लिए कोई संसाधन नहीं। इसके अलावा, संभवतः अनुकूलित (जैसे Files.readAllBytesफ़ाइल के आकार के लिए उपयुक्त बाइट सरणी आवंटित)।


7

मुझे बताया गया है कि Source.fromFile समस्याग्रस्त है। व्यक्तिगत रूप से, मुझे Source.fromFile के साथ बड़ी फ़ाइलों को खोलने में समस्याएं हुई हैं और जावा इनपुटस्ट्रीम का सहारा लेना पड़ा है।

एक और दिलचस्प समाधान स्केलैक्स का उपयोग कर रहा है। यहाँ कुछ अच्छी तरह से टिप्पणी की गई कोड का एक उदाहरण है जो स्केलड हेल्पर्स के साथ एक फ़ाइल खोलने के लिए ManagedResource का उपयोग करके एक लॉग फ़ाइल खोलता है: http://pastie.org/paste/420714


6

Scala.io.Source पर getLines () का उपयोग करके लाइन टर्मिनेटर (\ n, \ r, \ r \ n, आदि) के लिए कौन से वर्णों का उपयोग किया गया था

निम्नलिखित को इसे चरित्र-दर-चरित्र संरक्षित करना चाहिए, और अत्यधिक स्ट्रिंग संघनन (प्रदर्शन समस्याएं) नहीं करता है:

def fileToString(file: File, encoding: String) = {
  val inStream = new FileInputStream(file)
  val outStream = new ByteArrayOutputStream
  try {
    var reading = true
    while ( reading ) {
      inStream.read() match {
        case -1 => reading = false
        case c => outStream.write(c)
      }
    }
    outStream.flush()
  }
  finally {
    inStream.close()
  }
  new String(outStream.toByteArray(), encoding)
}

6

एक और: https://github.com/pathikrit/better-files#streams-and-codecs

मेमोरी में सामग्री को लोड किए बिना किसी फ़ाइल को खिसकाने के विभिन्न तरीके:

val bytes  : Iterator[Byte]            = file.bytes
val chars  : Iterator[Char]            = file.chars
val lines  : Iterator[String]          = file.lines
val source : scala.io.BufferedSource   = file.content 

आप किसी भी चीज़ के लिए अपने स्वयं के कोडेक की आपूर्ति कर सकते हैं, जो एक पठन / लेखन करता है (यह मानता है scala.io.Codec.default यदि आप एक प्रदान नहीं करते हैं):

val content: String = file.contentAsString  // default codec
// custom codec:
import scala.io.Codec
file.contentAsString(Codec.ISO8859)
//or
import scala.io.Codec.string2codec
file.write("hello world")(codec = "US-ASCII")

5

जावा में, कॉमन्सियो लाइब्रेरी का उपयोग करते हुए:

FileUtils.readFileToString(file, StandardCharsets.UTF_8)

साथ ही, यहां कई जवाब चारसेट को भूल जाते हैं। इसे हमेशा स्पष्ट रूप से प्रदान करना बेहतर है, या यह एक दिन हिट होगा।


4

रूबी सिंटैक्स (और शब्दार्थ को व्यक्त करने) के लिए एक फ़ाइल खोलने और पढ़ने के लिए, इस निहित वर्ग (स्केल 2.10 और ऊपरी) पर विचार करें,

import java.io.File

def open(filename: String) = new File(filename)

implicit class RichFile(val file: File) extends AnyVal {
  def read = io.Source.fromFile(file).getLines.mkString("\n")
}

इस तरह,

open("file.txt").read

3

कुछ लोगों ने scala.io.Source का उल्लेख किया है का है, कनेक्शन लीक के कारण बचना सबसे अच्छा है।

संभवत: स्केलक्स और प्योर जावा लिबास जैसे कॉमन्स-आईओओ सबसे अच्छे विकल्प हैं जब तक कि नए इनक्यूबेटर प्रोजेक्ट (यानी स्काला-आईओ) का विलय नहीं हो जाता।


3

आप फ़ाइलों को पढ़ने और प्रोसेस करने के लिए scala io से Path का उपयोग कर सकते हैं।

import scalax.file.Path

अब आप इसका उपयोग करके फ़ाइल पा सकते हैं: -

val filePath = Path("path_of_file_to_b_read", '/')
val lines = file.lines(includeTerminator = true)

आप टर्मिनेटर भी शामिल कर सकते हैं लेकिन डिफ़ॉल्ट रूप से यह गलत पर सेट है।


3

एक (बड़ी) फ़ाइल को तेजी से पढ़ने / अपलोड करने के लिए , उदाहरण के लिए, bufferSize( Source.DefaultBufSizeसेट 2048) के आकार को बढ़ाने पर विचार करें ,

val file = new java.io.File("myFilename")
io.Source.fromFile(file, bufferSize = Source.DefaultBufSize * 2)

नोट Source.scala । आगे की चर्चा के लिए, स्कैला फास्ट टेक्स्ट फाइल को पढ़ें और मेमोरी में अपलोड करें


3

आपको हर एक पंक्ति को पार्स करने की आवश्यकता नहीं है और फिर उन्हें फिर से व्यवस्थित करें ...

Source.fromFile(path)(Codec.UTF8).mkString

मैं इसका उपयोग करना पसंद करता हूं:

import scala.io.{BufferedSource, Codec, Source}
import scala.util.Try

def readFileUtf8(path: String): Try[String] = Try {
  val source: BufferedSource = Source.fromFile(path)(Codec.UTF8)
  val content = source.mkString
  source.close()
  content
}

आपको स्ट्रीम बंद कर देना चाहिए - यदि त्रुटि होती हैval content = source.mkString
Andrzej Jozwik

के लिए +1 Codec। मुझे परीक्षण विफल हो गया sbt testक्योंकि इसे सेट नहीं किया जा सकता है, जबकि इंटेलीज की टेस्ट कमांड सभी परीक्षणों को पास करती है। और आप इसdef using से उपयोग कर सकते हैं
मिखाइल Ionkin

3

यदि आपको किसी तृतीय-पक्ष निर्भरता पर कोई आपत्ति नहीं है, तो आपको मेरे OS-Lib लाइब्रेरी का उपयोग करने पर विचार करना चाहिए । यह फाइल पढ़ना / लिखना और फाइलसिस्टम के साथ काम करना बहुत सुविधाजनक बनाता है:

// Make sure working directory exists and is empty
val wd = os.pwd/"out"/"splash"
os.remove.all(wd)
os.makeDir.all(wd)

// Read/write files
os.write(wd/"file.txt", "hello")
os.read(wd/"file.txt") ==> "hello"

// Perform filesystem operations
os.copy(wd/"file.txt", wd/"copied.txt")
os.list(wd) ==> Seq(wd/"copied.txt", wd/"file.txt")

के लिए एक लाइन सहायकों के साथ बाइट्स पढ़ने , मात्रा पढ़ने , लाइनों को पढ़ने , और कई अन्य उपयोगी / आम आपरेशन


2

स्पष्ट प्रश्न "आप पूरी फ़ाइल में क्यों पढ़ना चाहते हैं?" यह स्पष्ट रूप से एक स्केलेबल समाधान नहीं है यदि आपकी फाइलें बहुत बड़ी हैं। scala.io.Sourceआप एक बैकअप देता Iterator[String]सेgetLines विधि है, जो बहुत ही उपयोगी और संक्षिप्त है।

एक File, Readerया एक के रूप में बदलने के लिए अंतर्निहित जावा IO उपयोगिताओं का उपयोग करते हुए अंतर्निहित रूपांतरण के साथ आना बहुत ज्यादा काम नहीं InputStreamहै String। मुझे लगता है कि स्केलेबिलिटी की कमी का मतलब है कि वे मानक एपीआई में इसे नहीं जोड़ने के लिए सही हैं।


12
गंभीरता से? आप नियमित रूप से कितनी फ़ाइलों को नियमित रूप से पढ़ते हैं जिनकी वास्तविक समस्याएं मेमोरी में फिट होती हैं? मैं कभी नहीं निपटा है कार्यक्रमों के विशाल बहुमत में फ़ाइलों के विशाल बहुमत आसानी से स्मृति में फिट करने के लिए काफी छोटे हैं। सच कहूँ तो, बड़ी डेटा फ़ाइलें अपवाद हैं, और आपको यह महसूस करना चाहिए कि आप उन्हें पढ़ / लिख रहे हैं, उसी के अनुसार और प्रोग्राम करें।
क्रिस्टोफर

8
oxbow_lakes, मैं असहमत हूं। छोटी फ़ाइलों को शामिल करने वाली कई स्थितियाँ हैं जिनका आकार भविष्य में नहीं बढ़ेगा।
ब्रेंडन OConnor

4
मैं मानता हूं कि वे अपवाद हैं - लेकिन मुझे लगता है कि इसीलिए रीड-पूरी-फ़ाइल-इन-मेमोरी जेडडीके या स्काला एसडीके दोनों में नहीं है। यह आपके लिए खुद को लिखने के लिए एक 3 लाइन उपयोगिता विधि है: इसके ऊपर जाओ
ऑक्सबो_लैक्स

1

हर लाइन को प्रिंट करें, जैसे जावा बफ़ररएडर रीड एवरी लाइन का उपयोग करें, और इसे प्रिंट करें:

scala.io.Source.fromFile("test.txt" ).foreach{  print  }

बराबर:

scala.io.Source.fromFile("test.txt" ).foreach( x => print(x))

0
import scala.io.source
object ReadLine{
def main(args:Array[String]){
if (args.length>0){
for (line <- Source.fromLine(args(0)).getLine())
println(line)
}
}

तर्कों में आप फ़ाइल पथ दे सकते हैं और यह सभी पंक्तियों को वापस कर देगा


3
यह क्या प्रस्ताव है कि अन्य जवाब नहीं है?
jwvh

अन्य उत्तरों को नहीं देखा ... बस सोचा था कि मैं यहां पोस्ट किए गए योगदान दे सकता हूं ... उम्मीद है कि इससे किसी को नुकसान नहीं होगा :)
अपूर्वा

1
आपको वास्तव में उन्हें पढ़ना चाहिए। अधिकांश काफी जानकारीपूर्ण हैं। यहां तक ​​कि जो 8 साल पुराने हैं, उनके पास प्रासंगिक जानकारी है।
jwvh
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.