大容量ファイルのストリーミング
すべてを読み込まずにファイルを処理します
「大容量ファイルのストリーミング」はCoddyKit上の無料Go Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはGo Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Go Academyコースには全4レッスンが含まれています。
すべて読み込むことの問題
数GBのファイルをos.ReadFileでメモリに読み込むと、RAMを使い果たす可能性があります。代わりにストリーミング処理を行い、データが到着したらチャンク単位で処理してください。
ストリーミングの考え方
ストリーミングとは、一度にメモリ上に保持するデータを小さな範囲に限定することです。バッファリングと組み合わせると、メモリ使用量を一定に保ったまま、任意の大きさの入力を処理できます。
Scannerによる行単位の処理
テキストの場合、リーダーに対してbufio.Scannerを使うと、ファイルサイズに関係なく1行ずつ処理できます。ここではstrings.Readerでファイルをシミュレートしています。
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
src := strings.NewReader("alpha\nbeta\ngamma")
s := bufio.NewScanner(src)
for s.Scan() {
fmt.Println("processed:", s.Text())
}
}読み込まずにカウントする
メモリ上にほとんどデータを保持せずに、大規模なストリームの統計を計算できます。
package main
import (
"bufio"
"fmt"
"strings"
)
func main() {
s := bufio.NewScanner(strings.NewReader("a\nbb\nccc"))
total := 0
for s.Scan() {
total += len(s.Text())
}
fmt.Println("total chars:", total)
}固定サイズのチャンク
バイナリデータの場合は、Readを使って固定サイズのバッファに読み込みます。nは、格納されたバイト数を示します。
package main
import (
"fmt"
"io"
"strings"
)
func main() {
src := strings.NewReader("0123456789")
buf := make([]byte, 4)
for {
n, err := src.Read(buf)
if n > 0 {
fmt.Printf("chunk: %s\n", buf[:n])
}
if err == io.EOF {
break
}
}
}ストリーミングにはio.Copyを使う
io.Copy(dst, src)は小さな内部バッファを使って、リーダーからライターへすべてのデータをストリーミングします。データ全体を読み込む必要はありません。
package main
import (
"io"
"os"
"strings"
)
func main() {
src := strings.NewReader("streamed straight through\n")
io.Copy(os.Stdout, src)
}ReaderとWriterのバッファを組み合わせる
両端をbufioでラップすると、効率的なストリーミング変換を行えます。バッファ付きで読み取り、処理し、バッファ付きで書き込んで、フラッシュします。
package main
import (
"bufio"
"os"
"strings"
)
func main() {
r := bufio.NewScanner(strings.NewReader("one\ntwo"))
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
for r.Scan() {
w.WriteString(r.Text() + "!\n")
}
}メモリ使用量が一定になる保証
バッファサイズが固定されているため、入力が1KBでも1TBでもメモリ使用量は変わりません。これがストリーミングの最大の利点です。
よくあるミスを避ける
- 大きなファイルに対して
os.ReadFileを呼び出さない - エラーを確認する前に、必ず
nバイトを処理する - バッファ付きWriterでは
Flush()を忘れない
ストリームを変換する
ここではストリームから各行を読み取りながら大文字に変換し、一度にメモリ上に保持するのは1行だけにしています。
package main
import (
"bufio"
"os"
"strings"
)
func main() {
s := bufio.NewScanner(strings.NewReader("hi\nthere"))
w := bufio.NewWriter(os.Stdout)
defer w.Flush()
for s.Scan() {
w.WriteString(strings.ToUpper(s.Text()) + "\n")
}
}ストリーミングを使う場面
入力サイズが大きい、または不明な場合や、段階的に処理できる場合はストリーミングを使用します。すべてのデータを同時に必要とする小さく上限の決まったデータの場合に限り、全体を読み込んでください。
理解度チェック
ストリーミングについての知識を確認しましょう。
まとめ
データ全体を読み込まずに大規模なデータを処理する方法を学びました。
- テキストを行単位で処理するにはScanner
- バイナリデータをチャンク単位で処理するには固定サイズの
Read - ストリーム間の処理には
io.Copy - 両端をバッファリングし、Writerをフラッシュして、メモリ使用量を一定に保つ
よくある質問
「大容量ファイルのストリーミング」レッスンは無料ですか?
はい。「大容量ファイルのストリーミング」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Go Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Go Academyコースには全4レッスンが含まれています。
「大容量ファイルのストリーミング」で何を学びますか?
すべてを読み込まずにファイルを処理します ブラウザで直接実行するハンズオンコードでGo Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Go Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのGo Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「大容量ファイルのストリーミング」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このGo Academyレッスンでコードを書いて実行できますか?
はい。すべてのGo Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- バッファ付きReader
- Scanner
- バッファ付きWriter
- 大容量ファイルのストリーミング