1. 序章

Groovy では、Javaと同じようにI / Oを操作できますが、 Groovyは、JavaのI/O機能をいくつかのヘルパーメソッドで拡張します。

このチュートリアルでは、ファイルの読み取りと書き込み、ファイルシステムのトラバース、Groovyのファイル拡張メソッドを介したデータとオブジェクトのシリアル化について説明します。

該当する場合は、関連するJavaの記事にリンクして、Javaの同等の記事と簡単に比較できるようにします。

2. ファイルの読み取り

Groovyは、ファイルの読み取りに便利な機能を eachLine メソッド、BufferedReaderおよびInputStreamを取得するメソッド、および方法で追加します。 1行のコードですべてのファイルデータを取得します。

Java7とJava8は、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. InputStreamで読み取る

withReaderおよびnewReaderと同様に、 Groovyは、InputStreamsを簡単に操作するためのメソッドも提供します。 InputStream でテキストを読み取ることができ、Groovyはその機能を追加しますが、InputStreamはバイナリデータに最も一般的に使用されます。

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 と同様に、 newInputStream、を使用する場合は、 InputStream リソースを自分で閉じる必要がありますが、withInputStreamを使用する場合は閉じないでください。

2.4. 他の方法を読む

Groovyが1つのステートメントですべてのファイルデータを取得するために持っているいくつかの方法を見て、読み物の主題を終えましょう。

ファイルの行をListに入れたい場合は、 collect を使用して、イテレーターitをクロージャーに渡すことができます。

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. ファイルの書き込み

ファイルへの書き込みを開始する前に、出力するテキストを設定しましょう。

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)
}

newOutputStreamOutputStreamオブジェクトを取得し、それを使用していくつかのバイトを書き込みましょう。

byte[] outBytes = [44, 88, 22]
def os = new File(outputFileName).newOutputStream()
os.write(outBytes)
os.close()

InputStream BufferedReader 、および BufferedWriter と同様に、 newOutputStream [を使用する場合は、OutputStreamを自分で閉じる必要があります。 X186X]。

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 を使用してすべてのファイルを再帰的にリストし、FILESFileTypeを指定してみましょう。

new File('src/main').eachFileRecurse(FileType.FILES) { file ->
    println "$file.parent $file.name"
}

eachFile メソッドは、ディレクトリではなくファイルへのパスを指定すると、IllegalArgumentExceptionをスローします。

Groovyは、ディレクトリのみを操作するためのeachDirメソッドも提供します。 eachDir とそのバリアントを使用して、eachFileで使用するのと同じことを実行できます。 DIRECTORIESのFileType

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. トラバースを使用したファイルの一覧表示

より複雑なディレクトリトラバーサルのユースケースでは、トラバーサルメソッドを使用できます。 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を使用して、プリミティブデータフィールドシリアル化できます。 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 taskRead

new File('src/main/resources/ioSerializedObject.txt').withObjectInputStream { is ->
    taskRead = is.readObject()
}

使用したメソッドwithObjectOutputStreamおよびwithObjectInputStreamは、他の with * メソッドと同様に、ストリームをクロージャーに渡し、リソースのクローズを適切に処理します。 。

6. 結論

この記事では、Groovyが既存のJavaファイルI/Oクラスに追加する機能について説明しました。 この機能を使用して、ファイルの読み取りと書き込み、ディレクトリ構造の操作、およびデータとオブジェクトのシリアル化を行いました。

ヘルパーメソッドのいくつかに触れただけなので、 Groovyのドキュメントを調べて、JavaのI/O機能に他に何が追加されるかを確認する価値があります。

サンプルコードは、GitHubから入手できます。