Goアプリケーションの多くにおいて、巨大なファイルの効率的な処理は非常に重要です。ファイルをメモリ全体に読み込むのではなく、行単位で読み込むことは、主要な最適化戦略です。この記事では、Goの標準ライブラリを用いて、ベストプラクティスとエラー処理に焦点を当てながら、これを効率的に実現する方法を詳述します。
目次
パッケージのインポート
主に、バッファリングされたI/Oのためにbufio
パッケージを使用します。これは、生のバイト単位の読み込みと比べてパフォーマンスを大幅に向上させます。os
パッケージはファイル操作を処理します。
import (
"bufio"
"fmt"
"os"
)
bufio.Scanner
による行単位の読み込み
bufio.Scanner
は理想的なツールです。チャンク単位でデータを読み込み、効率のためにバッファリングします。そのScan()
メソッドは次の行を取得し、成功した場合はtrue
、ファイルの終端の場合はfalse
を返します。
func processFileLineByLine(filePath string) {
file, err := os.Open(filePath)
if err != nil {
fmt.Printf("ファイル '%s' のオープンエラー: %vn", filePath, err)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
// 各行を処理する (例: fmt.Println(line))
}
if err := scanner.Err(); err != nil {
fmt.Printf("ファイル '%s' の読み込みエラー: %vn", filePath, err)
}
}
完全な例
この例では、my_file.txt
という名前のファイルから行を読み込んで処理する方法を示しています。同じディレクトリにこのファイルを作成してください。
package main
import (
"bufio"
"fmt"
"os"
)
// ... (上記のprocessFileLineByLine関数) ...
func main() {
filePath := "my_file.txt"
processFileLineByLine(filePath)
}
スキャナのバッファサイズ調整
非常に大きなファイルや行の場合、scanner.Buffer()
を使用してbufio.Scanner
のバッファサイズを調整します。バッファを大きくするとシステムコールが減少しますが、メモリ消費量が増加します。ファイルの特性と利用可能なリソースに基づいて、バランスを見つける必要があります。
scanner := bufio.NewScanner(file)
bufferSize := 1024 * 1024 // 1MB バッファ
scanner.Buffer(make([]byte, bufferSize), bufferSize)
堅牢なエラー処理
ファイルを開いた後とスキャンした後に、常にエラーを確認してください。defer file.Close()
ステートメントにより、エラーが発生した場合でもファイルが確実に閉じられます。分かりやすいエラーメッセージはデバッグに役立ちます。