1. 概要

このチュートリアルでは、バイナリ入力ストリームをScalaでテキストデータに変換する方法を確認します。 低レベルでは、Scalaはパッケージjava.ioの標準Javaクラスを使用します。 ただし、いくつかのユーティリティも提供されているため、それらの作業が簡単になります。

たとえば、scala.ioパッケージ内のクラスSourceは、java.io.InputStreamインスタンスから文字列データへのスムーズな変換を提供するため、その機能についても説明します。

2. ソースインスタンスの作成

Source コンパニオンオブジェクトは、さまざまなInputStream実装に対応するインスタンスを作成するための便利なファクトリメソッドを提供します。 最も一般的な使用法のいくつかを調べてみましょう。

説明のために、メソッドfromUrlを介してreadリモートデータを読み取ることができます。

lazy val sourceFromUrl: Source = Source.fromURL("https://google.com")

この特定の例では、Googleホームページのコンテンツをフェッチしますが、実際には、APIからJSONをクエリしてさらに使用することができます。

アプリケーションのクラスパスからデータを読み取るには、fromResourceを使用できます。

lazy val sourceFromClassPath: Source = Source.fromResource("com.baeldung.scala.io/file_in_classpath.txt")

この方法の一般的な使用例は、resourcesフォルダーに配置されたファイルからテストデータを読み取ることです。

別のSourceファクトリメソッドfromFileを使用すると、ファイルからコンテンツを読み取ることができます

lazy val sourceFromFile: Source = Source.fromFile("./some_text_file")
lazy val sourceFromFileWithCustomEncoder: Source = Source.fromFile("./some_text_file", enc = "Cp1252")

コード例でわかるように、オーバーロードされたバージョンがいくつか含まれています。 最初のものはデフォルトのUTF-8エンコーダーを使用してバイトをテキストに変換しますが、2番目のものは提供されたカスタムエンコーダーを使用します。

上記の例にリストされているものに加えて、 Source には、クラスソースコードにある他のいくつかの便利なファクトリメソッドも含まれています。

3. ソースでの文字列データの処理

Source インスタンスを取得する場合、いくつかのオプションがあります。 まず、mkStringメソッドを使用して、基になるストリームデータ全体をプレーンな文字列に熱心に変換できます。

val oneLineSource = Source.fromResource("com.baeldung.scala.io/one_line_string.txt")
try {
  oneLineSource.mkString shouldEqual "One line string"
} finally {
  oneLineSource.close()
}

次に、よりきめ細かい処理が必要な場合は、メソッドgetLinesを使用できます。 このメソッドはIterator[String] インスタンスを返すため、すべての行を順番に処理できます。

 // Every line in the test file starts with the 'String' prefix
 val fourLinesSource = Source.fromResource("com.baeldung.scala.io/four_lines_string.txt")
 try {
   fourLinesSource.getLines().foreach(line => assert(line.startsWith("String")))
 } finally {
  fourLinesSource.close()
}

また、上記の両方の例で try /finallyブロックの使用法を強調することが重要です。 ファイルまたはソケット記述子のリークを防ぐために、ソースデータの処理が終了したら、 close()メソッドを呼び出してリソースを適切に解放する必要があります。

4. 大きなまたは無限のInputSreamsの処理

残念ながら、さまざまなデータソースを操作する場合、遭遇するすべてのデータがメモリに収まるほど小さいわけではありません。 したがって、このような場合、熱心なアプローチは機能しません。

幸いなことに、イテレータを返す Sourceメソッドはメモリセーフであり、大規模または無限のストリームでの作業に使用できます。 さらに、クラス Source 自体は、 Iterator[Char]特性の実装です。 したがって、無限ストリームの部分処理にそのメソッドを使用できます。

val infiniteSource = Source.fromIterable {
  new Iterable[Char] {
    override def iterator: Iterator[Char] = Iterator.continually('A')
  }
}
infiniteSource.slice(100000, 100010).mkString shouldEqual "AAAAAAAAAA"

上記の例は純粋に合成ですが、大規模なデータを処理するゲノムデータファイルなどの実際のソースに適用できるアプローチを示しています。

5. 結論

このチュートリアルでは、 scala.io.Source クラスの機能のいくつかが、ScalaでInputStreamデータソースからテキストデータへの変換を容易にするのにどのように役立つかを探りました。

いつものように、すべての例を含むソースコードは、GitHubから入手できます。