Scalaでファイル全体をメモリに読み込むための単純で標準的な方法は何ですか? (理想的には、文字エンコーディングを制御します。)
私が思い付くことができる最高のものは:
scala.io.Source.fromPath("file.txt").getLines.reduceLeft(_+_)
あるいは、私は Javaのひどい意味のイディオム のうちの1つを使用することになっています。
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()
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()
上記のコードに関するもう1つの問題は、その実装の性質上、非常に遅いということです。大きなファイルの場合は、次のものを使用してください。
source.getLines mkString "\n"
Danielのソリューションを拡張するためだけに、ファイル操作を必要とするファイルに次のインポートを挿入することで物事を大幅に短縮することができます。
import scala.io.Source._
これで、あなたは今することができます:
val lines = fromFile("file.txt").getLines
ファイル全体を1つのString
に読み込むことには用心深いでしょう。それは非常に悪い習慣です。 getLines
メソッドは、タイプIterator[String]
の値を返します。これは事実上ファイルへの怠惰なカーソルなので、メモリ不足を招くことなく必要なデータだけを調べることができます。
ああ、そしてSource
に関するあなたの暗黙の質問に答えるために:はい、それは標準的なI/Oライブラリです。ほとんどのコードは、その下位レベルのインターフェースと既存のフレームワークとのより良い互換性のためにJava.io
を使用しますが、特に単純なファイル操作の場合は、Source
を使用する必要があります。
// for file with utf-8 encoding
val lines = scala.io.Source.fromFile("file.txt", "utf-8").getLines.mkString
(編集:これはscala 2.9ではうまくいかないし、おそらく2.8でもうまくいかない)
トランクを使用:
scala> io.File("/etc/passwd").Slurp
res0: String =
##
# User Database
#
... etc
import Java.nio.charset.StandardCharsets._
import Java.nio.file.{Files, Paths}
new String(Files.readAllBytes(Paths.get("file.txt")), UTF_8)
文字エンコードを制御します。クリーンアップするリソースはありません。また、おそらく最適化されています(例:Files.readAllBytes
はファイルのサイズに適したバイト配列を割り当てる)。
Source.fromFileには問題があると言われました。個人的には、Source.fromFileで大きなファイルを開くのに問題があり、Java InputStreamに頼らなければなりませんでした。
もう一つの興味深い解決策はscalaxを使うことです。これはscalaxヘルパーでファイルを開くためにManagedResourceを使ってログファイルを開くいくつかのよくコメントされたコードの例です: http://pastie.org/pastes/420714
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)
}
Javaと同じように、CommonsIOライブラリを使用します。
FileUtils.readFileToString(file, StandardCharsets.UTF_8)
また、ここでの多くの答えはCharsetを忘れています。それを常に明示的に提供することがより良いです、さもなければそれはいつの日かヒットします。
ファイルを開いたり読み込んだりするためのRuby構文をエミュレートする(そして意味を伝える)ために、この暗黙のクラス(Scala 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
もう一つ: 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")
scala ioからのパスを使ってファイルを読み込んで処理することもできます。
import scalax.file.Path
今、あなたはこれを使ってファイルパスを取得することができます: -
val filePath = Path("path_of_file_to_b_read", '/')
val lines = file.lines(includeTerminator = true)
ターミネータを含めることもできますが、デフォルトではfalseに設定されています。
少数の人が述べたように scala.io.Source は接続リークのため避けるべきです。
新しいインキュベータプロジェクト(すなわちscala-io)がマージされるまでは、おそらくscalaxとcommons-ioのような純粋なJavaライブラリが最良の選択肢です。
(大きな)ファイルの全体的な読み取り/アップロードを高速化するには、次のようにbufferSize
(Source.DefaultBufSize
を2048
に設定)のサイズを増やすことを検討してください。
val file = new Java.io.File("myFilename")
io.Source.fromFile(file, bufferSize = Source.DefaultBufSize * 2)
注 Source.scala 。さらなる議論については、 Scalaの高速テキストファイルを読み、メモリにアップロードする を参照してください。
明白な問題は、"なぜファイル全体を読み込むのですか?"ファイルが非常に大きくなった場合、これは明らかにスケーラブルな解決策ではありません。 scala.io.Source
はgetLines
メソッドからIterator[String]
を返すので、非常に便利で簡潔です。
基礎となるJava IOユーティリティを使用してFile
、Reader
、またはInputStream
をString
に変換する暗黙的な変換を行うのは、あまり面倒な作業ではありません。私はスケーラビリティの欠如が標準のAPIにこれを追加しないことが彼らが正しいということを意味すると思います。
import scala.io.source
object ReadLine{
def main(args:Array[String]){
if (args.length>0){
for (line <- Source.fromLine(args(0)).getLine())
println(line)
}
}
引数にはファイルパスを指定でき、すべての行を返します。
サードパーティの依存関係を気にしないのであれば、my OS-Lib library の使用を検討してください。これにより、ファイルの読み書きやファイルシステムの操作が非常に便利になります。
// 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")
バイトの読み込み 、 チャンクの読み込み 、 行の読み込み 、およびその他多くの便利な/一般的な操作のための1行ヘルパー
java BufferedReaderを使用してすべての行を読み取り、それを印刷します。
scala.io.Source.fromFile("test.txt" ).foreach{ print }
同等のもの:
scala.io.Source.fromFile("test.txt" ).foreach( x => print(x))
1行ごとに解析してから再び連結する必要はありません。
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
}