GroovyのI / Oガイド

  • link:/category/programming/ [プログラミング]

  • Groovy

1. 前書き

link:/groovy-language[Groovy]ではJavaと同じようにI / Oを使用できますが、* Groovyは多くのヘルパーメソッドを使用してJavaのI / O機能を拡張します。
このチュートリアルでは、ファイルの読み取りと書き込み、ファイルシステムの走査、Groovyの_File_拡張メソッドによるデータとオブジェクトのシリアル化について説明します。
該当する場合、関連するJava記事にリンクして、Javaの同等物と簡単に比較できるようにします。

2. ファイルを読む

Groovyは、https://www.baeldung.com/groovy-file-read [reading files]の便利な機能を_eachLine_メソッド、__ BufferedReader__sおよび__InputStream__sを取得するメソッド、1行ですべてのファイルデータを取得する方法の形式で追加します。コードの。
Java 7およびJava 8は、https://www.baeldung.com/reading-file-in-java [Javaでのファイルの読み取り]を同様にサポートしています。

2.1. _eachLine_を使用した読み取り

テキストファイルを扱う場合、各行を読み取って処理する必要があります。 * Groovyは_eachLine_メソッドで_java.io.File_に便利な拡張機能を提供します*:
def lines = []

new File('src/main/resources/ioInput.txt').eachLine { line ->
    lines.add(line)
}
_eachLine_に提供されるクロージャーには、便利なオプションの行番号もあります。 行番号を使用して、ファイルから特定の行のみを取得しましょう。
def lineNoRange = 2..4
def lines = []

new File('src/main/resources/ioInput.txt').eachLine { line, lineNo ->
    if (lineNoRange.contains(lineNo)) {
        lines.add(line)
    }
}
*デフォルトでは、行番号は1から始まります。*最初の行番号として使用する値は、_eachLine_メソッドの最初のパラメーターとして渡すことで提供できます。
行番号をゼロから始めましょう。
new File('src/main/resources/ioInput.txt').eachLine(0, { line, lineNo ->
    if (lineNoRange.contains(lineNo)) {
        lines.add(line)
    }
})
__eachLineで例外がスローされた場合、__ ** Groovyはファイルリソースを確実に閉じます**。 Javaの_try-with-resources_または_try-finally_によく似ています。

2.2. リーダーで読む

Groovy _File_オブジェクトから_BufferedReader_を簡単に取得することもできます。 _withReader_を使用して、_BufferedReader_をファイルオブジェクトに取得し、クロージャーに渡すことができます。
def actualCount = 0
new File('src/main/resources/ioInput.txt').withReader { reader ->
    while(reader.readLine()) {
        actualCount++
    }
}
_eachLine_と同様に、_withReader_メソッドは、例外がスローされたときにリソースを自動的に閉じます。
場合によっては、_BufferedReader_オブジェクトを使用可能にしたい場合があります。 たとえば、パラメータとして1つを取るメソッドを呼び出すことを計画する場合があります。 これには_newReader_メソッドを使用できます。
def outputPath = 'src/main/resources/ioOut.txt'
def reader = new File('src/main/resources/ioInput.txt').newReader()
new File(outputPath).append(reader)
reader.close()
これまで見てきた他のメソッドとは異なり、*この方法で_BufferedReader_を取得するときは、_BufferedReader_リソースを閉じる必要があります。*

2.3. InputStreamsを使用した読み取り

_withReader_および_newReader_と同様に、* Groovyは__InputStream__s *を簡単に操作するためのメソッドも提供します。 __InputStream__sでテキストを読み取ることができ、Groovyはその機能を追加しますが、__ InputStream__sはバイナリデータに最もよく使用されます。
closure_withInputStream_を使用して、_InputStream_をクロージャーに渡し、バイトを読み取りましょう。
byte[] data = []
new File("src/main/resources/binaryExample.jpg").withInputStream { stream ->
    data = stream.getBytes()
}
_InputStream_オブジェクトが必要な場合は、_newInputStream_を使用してオブジェクトを取得できます。
def outputPath = 'src/main/resources/binaryOut.jpg'
def is = new File('src/main/resources/binaryExample.jpg').newInputStream()
new File(outputPath).append(is)
is.close()
_BufferedReader_と同様に、_withInputStream_を使用するときではなく、_newInputStream_を使用するときに_InputStream_リソースを閉じる必要があります。

2.4. 他の方法を読む

Groovyがすべてのファイルデータを1つのステートメントで取得するために使用するいくつかのメソッドを見て、読書のテーマを仕上げましょう。
_List_にファイルの行が必要な場合は、クロージャに渡されるイテレータ_it_で_collect_を使用できます。
def actualList = new File('src/main/resources/ioInput.txt').collect {it}
ファイルの行を_Strings_の配列に取得するには、_as String [] _を使用できます。
def actualArray = new File('src/main/resources/ioInput.txt') as String[]
短いファイルの場合、_text_を使用して_String_の内容全体を取得できます。
def actualString = new File('src/main/resources/ioInput.txt').text
また、バイナリファイルを使用する場合、_bytes_メソッドがあります。
def contents = new File('src/main/resources/binaryExample.jpg').bytes

3. ファイルを書く

link:/java-write-to-file [ファイルへの書き込み]を開始する前に、出力するテキストを設定しましょう。
def outputLines = [
    'Line one of output example',
    'Line two of output example',
    'Line three of output example'
]

3.1. ライターで書く

ファイルの読み取りと同様に、* _ File_オブジェクトから_BufferedWriter_を簡単に取得することもできます*。
_withWriter_を使用して_BufferedWriter_を取得し、クロージャーに渡します。
def outputFileName = 'src/main/resources/ioOutput.txt'
new File(outputFileName).withWriter { writer ->
    outputLines.each { line ->
        writer.writeLine line
    }
}
_withReader_を使用すると、例外が発生した場合にリソースが閉じられます。
Groovyには、_BufferedWriter_オブジェクトを取得するメソッドもあります。 _newWriter_を使用して_BufferedWriter_を取得しましょう。
def outputFileName = 'src/main/resources/ioOutput.txt'
def writer = new File(outputFileName).newWriter()
outputLines.forEach {line ->
    writer.writeLine line
}
writer.flush()
writer.close()
_newWriter_を使用するときは、_BufferedWriter_オブジェクトをフラッシュして閉じます。

3.2. 出力ストリームを使用した書き込み

バイナリデータを書き出す場合は、* _ withOutputStream_または_newOutputStream_ *を使用して_OutputStream_を取得できます。
_withOutputStream_を使用して、ファイルにいくつかのバイトを書き込みましょう。
byte[] outBytes = [44, 88, 22]
new File(outputFileName).withOutputStream { stream ->
    stream.write(outBytes)
}
_newOutputStream_で_OutputStream_オブジェクトを取得し、それを使用していくつかのバイトを書き込みましょう。
byte[] outBytes = [44, 88, 22]
def os = new File(outputFileName).newOutputStream()
os.write(outBytes)
os.close()
_InputStream _、_ BufferedReader_、および_BufferedWriter_と同様に、_newOutputStream_を使用する場合は、_OutputStream_を自分で閉じる必要があります。

3.3. <<演算子を使用した書き込み

ファイルへのテキストの書き込みは非常に一般的であるため、_ << _演算子はこの機能を直接提供します。
_ << _演算子を使用して、いくつかの簡単なテキスト行を記述しましょう。
def ln = System.getProperty('line.separator')
def outputFileName = 'src/main/resources/ioOutput.txt'
new File(outputFileName) << "Line one of output example${ln}" +
  "Line two of output example${ln}Line three of output example"

3.4. バイトを使用したバイナリデータの書き込み

*前の記事で、_bytes_フィールドにアクセスするだけで、バイナリファイルからすべてのバイトを取得できることがわかりました。*
同じ方法でバイナリデータを書きましょう。
def outputFileName = 'src/main/resources/ioBinaryOutput.bin'
def outputFile = new File(outputFileName)
byte[] outBytes = [44, 88, 22]
outputFile.bytes = outBytes

4. ファイルツリーの走査

  • Groovyは、ファイルツリーを操作する簡単な方法も提供します。*このセクションでは、eachFile _、 eachDir_、およびそれらのバリアントと_traverse_メソッドを使用してこれを行います。

4.1. _eachFile_を使用したファイルのリスト

_eachFile_を使用して、ディレクトリ内のすべてのファイルとディレクトリをリストしましょう。
new File('src/main/resources').eachFile { file ->
    println file.name
}
ファイルを操作する際のもう1つの一般的なシナリオは、ファイル名に基づいてファイルをフィルタリングする必要があることです。 _eachFileMatch_と正規表現を使用して、「io」で始まり「.txt」で終わるファイルのみをリストします。
new File('src/main/resources').eachFileMatch(~/io.*\.txt/) { file ->
    println file.name
}
  • eachFile_および_eachFileMatch_メソッドは、最上位ディレクトリのコンテンツのみをリストします。* Groovyでは、_FileType_をメソッドに渡すことで、_eachFile_メソッドが返す内容を制限することもできます。 オプションは、_ANY _、 FILES_、および_DIRECTORIES_です。

    _eachFileRecurse_を使用して、_FILES_の_FileType_を指定して、すべてのファイルを再帰的にリストします。
new File('src/main').eachFileRecurse(FileType.FILES) { file ->
    println "$file.parent $file.name"
}
_eachFile_メソッドは、ディレクトリではなくファイルへのパスを提供すると、_IllegalArgumentException_をスローします。
  • Groovyは、ディレクトリのみを操作するための_eachDir_メソッドも提供します。

    _eachFileRecurse_を使用してディレクトリを再帰的にリストします。
new File('src/main').eachFileRecurse(FileType.DIRECTORIES) { file ->
    println "$file.parent $file.name"
}
では、_eachDirRecurse_で同じことをしましょう。
new File('src/main').eachDirRecurse { dir ->
    println "$dir.parent $dir.name"
}

4.2. トラバースを使用したファイルのリスト

  • link:/java-nio2-file-visitor [より複雑なディレクトリトラバーサル]ユースケースでは、_traverse_メソッドを使用できます。* _eachFileRecurse_と同様に機能しますが、_FileVisitResult_オブジェクトを返す機能を提供します。処理を制御します。

    _src / main_ディレクトリで_traverse_を使用して、_groovy_ディレクトリの下のツリーの処理をスキップしましょう。
new File('src/main').traverse { file ->
   if (file.directory && file.name == 'groovy') {
        FileVisitResult.SKIP_SUBTREE
    } else {
        println "$file.parent - $file.name"
    }
}

5. データとオブジェクトの操作

5.1. プリミティブのシリアル化

Javaでは、_DataInputStream_および_DataOutputStream_を使用してlink:/java-serialization [プリミティブデータフィールドをシリアル化]できます。 Groovyは便利な拡張機能もここに追加します。
いくつかのプリミティブデータを設定しましょう。
String message = 'This is a serialized string'
int length = message.length()
boolean valid = true
次に、_withDataOutputStream_を使用してデータをファイルにシリアル化します。
new File('src/main/resources/ioData.txt').withDataOutputStream { out ->
    out.writeUTF(message)
    out.writeInt(length)
    out.writeBoolean(valid)
}
_withDataInputStream_を使用して読み返します。
String loadedMessage = ""
int loadedLength
boolean loadedValid

new File('src/main/resources/ioData.txt').withDataInputStream { is ->
    loadedMessage = is.readUTF()
    loadedLength = is.readInt()
    loadedValid = is.readBoolean()
}
他の_with * _メソッドと同様に、_withDataOutputStream_および_withDataInputStream_はストリームをクロージャーに渡し、適切に閉じられていることを確認します。

5.2. オブジェクトのシリアル化

  • GroovyはJavaの_ObjectInputStream_および_ObjectOutputStream_にも基づいており、Serializable *を実装するオブジェクトを簡単にシリアル化できます。

    最初に_Serializable_を実装するクラスを定義しましょう:
class Task implements Serializable {
    String description
    Date startDate
    Date dueDate
    int status
}
次に、ファイルにシリアル化できる_Task_のインスタンスを作成しましょう。
Task task = new Task(description:'Take out the trash', startDate:new Date(), status:0)
_Task_オブジェクトを手に、_withObjectOutputStream_を使用してファイルにシリアル化します。
new File('src/main/resources/ioSerializedObject.txt').withObjectOutputStream { out ->
    out.writeObject(task)
}
最後に、_withObjectInputStream_を使用して_Task_を読み直します。
Task taskRead

new File('src/main/resources/ioSerializedObject.txt').withObjectInputStream { is ->
    taskRead = is.readObject()
}
使用したメソッド_withObjectOutputStream_および_withObjectInputStream_は、他の_with * _メソッドで見られるように、ストリームをクロージャーに渡し、リソースのクローズを適切に処理します。

6. 結論

この記事では、Groovyが既存のJava File I / Oクラスに追加する機能を検討しました。 この機能を使用して、ファイルの読み取りと書き込み、ディレクトリ構造の操作、データとオブジェクトのシリアル化を行いました。
ヘルパーメソッドのいくつかに触れただけなので、http://docs.groovy-lang.org/docs/next/html/groovy-jdk/java/io/package-summary.html [Groovyのドキュメント] JavaのI / O機能に他に何が追加されるかを確認します。
サンプルコードはhttps://github.com/eugenp/tutorials/tree/master/core-groovy[over on GitHub]で入手できます。