はじめに
前回の記事の続きです。
前回の記事はこちら
ファイルのアップロード処理
前回はフォームの複数回送信の防止を行いました。
今回はファイルアップロード処理です。
早速下記のhtmlを書いてみましょう。upload.gptl
で保存します。
<html>
<head>
<title>ファイルアップロード</title>
</head>
<body>
<form enctype="multipart/form-data" action="http://127.0.0.1:9090/upload" method="post">
<input type="file" name="uploadfile" />
<input type="hidden" name="token" value="{{.}}"/>
<input type="submit" value="upload" />
</form>
</body>
</html>
長いので下記に gist
コードを貼り付けました。
https://gist.github.com/katsuobushiFPGA/594c5dcacf77b23929ed7ac68158ae2a
早速実行してみましょう。
どうやらうまくいってそうです。upload
関数を見ていきます。
if r.Method == "GET"
のパスは、 token
のチェックと、 htmlを描画している処理ですね。
これは前回までにやっていた部分です。
else
ケースを見てみます。
r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("uploadfile")
if err != nil {
fmt.Println(err)
return
}
この部分は、
上のコードでは、ファイルのアップロードを処理するためには
r.ParseMultipartForm
をコールする必要があります。引数にはmaxMemory
が表示されています。
ということですね。アップロードされたファイルを処理するものです。
defer file.Close()
fmt.Fprintf(w, "%v", handler.Header)
f, err := os.OpenFile("./test/"+handler.Filename, os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
io.Copy(f, file)
この部分は、
ParseMultipartForm
をコールした後、アップロードするファイルはmaxMemory
のサイズのメモリに保存されます。
もしファイルのサイズがmaxMemory
を超えた場合、残った部分はシステムのテンポラリファイルに保存されます。r.FormFile
によって上のファイルハンドルを取得することができます。
テンポラリの部分は、1個前のfile, handler, err := r.FormFile("uploadfile")
で開いていますね。
保存用のファイルオブジェクトを、handler.Filename
でファイル名を取得して作成していますね。
その後実例の中ではio.Copyを使ってファイルを保存しています。
取得できたファイルを、io.Copy
を使用してファイル保存がされていますね。
個々まで読んできて思ったのは、先程のアップロード処理は実は成功していませんでしたね。
4枚目のキャプチャのコンソール出力に、 open ./test/20170903_つきこ.png: The system cannot find the path specified.
と書いてあります。
test
フォルダを直下に作る必要がありそうです。
作ってみましょうか。
できてました!
最後にフォーム処理について読んでみます。
上の実例を通して、ファイルのアップロードには主に3ステップの処理があることが分かります:
- フォームに
enctype="multipart/form-data"
を追加する。- サーバで
r.ParseMultipartForm
をコールし、アップロードするファイルをメモリとテンポラリファイルに保存する。r.FormFile
を使用して、ファイルハンドルを取得し、ファイルに対して保存等の処理を行う。
なるほど・・・!
クライアントによるファイルのアップロード
クライアントのアップロードをエミュレート(擬似的な操作)できる機能があるようです。
早速試してみましょう。
(アップロードのテストとかが捗りそうですね!)
client.go
を作成してコピーしました。
サーバは起動しっぱなしで、 client.go
を実行してみましょう。
20170822_リーシャ.png
というのを直下にそのまま置きました。
これをアップロードする予定となります。
おぉ!うまく行ってますね!
おわりに
フォーム編はこれで終了となります。
明日からは、データベースへのアクセスですね。
各DBはDockerで用意しようかな~。