Goならわかるシステムプログラミング:第3章 io.Reader

01 Mar 2022, 23:37 By mosuke5

こんにちは、もーすけです。
「Goならわかるシステムプログラミング」を読み進めています。とてもいい本です。 読み進めながら実験していることを書いていきます。同じ本を読んでいる人の参考(寄り道?)になればと思います。 今回は「低レベルアクセスへの入り口2:io.Reader」です。


Goならわかるシステムプログラミングの学習シリーズ

問題への挑戦

本章は、問題に挑戦した結果だけまとめます。

Q3.1 ファイルのコピー

これはシンプルですね。os.Argsで引数とってCLI的に使えるようにしてみました。

package main

import (
	"io"
	"os"
)

func main() {
	oldFile, err := os.Open(os.Args[1])
	if err != nil {
		panic(err)
	}
	defer oldFile.Close()

	newFile, err := os.Create(os.Args[2])
	if err != nil {
		panic(err)
	}
	defer newFile.Close()

	io.Copy(newFile, oldFile)
}

Q3.2 テスト用の適当なサイズのファイルを作成

io.CopyNなど補助関数使うともっとシンプルにできると思います。

package main

import (
	"crypto/rand"
	"io"
	"os"
)

func main() {
	buffer := make([]byte, 1024)
	_, err := rand.Read(buffer)

	if err != nil {
		panic(err)
	}

	file, err := os.Create("tmp.txt")

	if err != nil {
		panic(err)
	}

	defer file.Close()

	io.WriteString(file, string(buffer))
}

でき上がったファイルのサイズもしっかり期待通りです。

$ go run main.go
$ ls -l tmp.txt
-rw-r--r--  1 mosuke5  staff  1024  4 13 17:31 tmp.txt

Q3.3 Zipファイルの書き込み

package main

import (
	"archive/zip"
	"io"
	"os"
	"strings"
)

func main() {
	file, err := os.Create("result.zip")
	if err != nil {
		panic(err)
	}

	zipWriter := zip.NewWriter(file)
	defer zipWriter.Close()

	aWriter, err := zipWriter.Create("a.txt")
	if err != nil {
		panic(err)
	}
	io.Copy(aWriter, strings.NewReader("aaaaa"))

	bWriter, err := zipWriter.Create("b.txt")
	if err != nil {
		panic(err)
	}
	io.Copy(bWriter, strings.NewReader("bbbbb"))
}
$ go run main.go
$ ls -l
total 16
-rw-r--r--  1 shinyamori  staff  457  4 13 21:33 main.go
-rw-r--r--  1 shinyamori  staff  244  4 13 21:34 result.zip

$ unzip result.zip 
Archive:  result.zip
  inflating: a.txt                   
  inflating: b.txt                   

$ ls -l
total 32
-rw-r--r--  1 shinyamori  staff    5 12 31  1979 a.txt
-rw-r--r--  1 shinyamori  staff    5 12 31  1979 b.txt
-rw-r--r--  1 shinyamori  staff  457  4 13 21:33 main.go
-rw-r--r--  1 shinyamori  staff  244  4 13 21:34 result.zip

$ cat a.txt 
aaaaa

$ cat b.txt 
bbbbb              

Q3.4 ZipファイルをWebサーバからダウンロード

package main

import (
	"archive/zip"
	"io"
	"net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/zip")
	w.Header().Set("Content-Disposition", "attachment; filename=result.zip")

	zipWriter := zip.NewWriter(w)
	defer zipWriter.Close()

	httpWriter, err := zipWriter.Create("a.txt")
	if err != nil {
		panic(err)
	}
	io.WriteString(httpWriter, "aaaaa")
}

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8080", nil)
}

Q3.5 CopyN

package main

import (
	"io"
	"os"
	"strconv"
	"strings"
)

func main() {
	writer := os.Stdout
	reader := strings.NewReader("123456789012345678901234567890")
	size, err := strconv.Atoi(os.Args[1])
	if err != nil {
		panic(err)
	}

	myCopyN(writer, reader, size)
}

func myCopyN(w io.Writer, r io.Reader, size int) {
	buffer := make([]byte, size)
	_, err := io.ReadFull(r, buffer)
	if err != nil {
		panic(err)
	}
	io.WriteString(w, string(buffer))
}
% go run main.go 0

% go run main.go 3
123

% go run main.go 10
1234567890

Q3.6 ストリーム総集編

package main

import (
	"io"
	"os"
	"strings"
)

var (
	computer    = strings.NewReader("COMPUTER")
	system      = strings.NewReader("SYSTEM")
	programming = strings.NewReader("PROGRAMMING")
)

func main() {
	var stream io.Reader
	charA := io.NewSectionReader(programming, 5, 1)
	charS := io.NewSectionReader(system, 0, 1)
	charC := io.NewSectionReader(computer, 0, 1)
	charI1 := io.NewSectionReader(programming, 8, 1)
	charI2 := io.NewSectionReader(programming, 8, 1)
	stream = io.MultiReader(charA, charS, charC, charI1, charI2)

	io.Copy(os.Stdout, stream)
}
記事の内容に関連した相談、仕事依頼したい New

記事の内容やクラウドネイティブ技術に関する相談、仕事依頼を開始しました。
仕事依頼、相談をしてみる

記事へのフィードバック

本記事に対して、フィードバックあればこちらのフォームからご記入ください。
記事の内容にフィードバックしてみる

このエントリーをはてなブックマークに追加