diff --git a/ja/ebook/04.5.md b/ja/ebook/04.5.md
new file mode 100644
index 00000000..98080934
--- /dev/null
+++ b/ja/ebook/04.5.md
@@ -0,0 +1,156 @@
+# 4.5 ファイルのアップロード処理
+ユーザによるファイルのアップロードを処理したいとします。例えば、現在Instagramのようなホームページを作成しているとします。ユーザが撮影した写真を保存する必要があります。このような要求はどのように実現するのでしょうか?
+
+フォームにファイルをアップロードさせるためには、まずformの`enctype`属性を追加する必要があります。`enctype`属性には以下の3つの状態あります:
+
+ application/x-www-form-urlencoded 送信前にすべての文字列をエンコードする(デフォルト)
+ multipart/form-data 文字列に対してエンコードしません。ファイルのアップロードウィジェットを含むフォームを使用するときはこの値が必要です。
+ text/plain 空白を"+"記号に置き換えます。ただし、特殊文字に対してエンコードは行われません。
+
+そのため、フォームのhtmlコードはこのようになります:
+
+
+
+ ファイルアップロード
+
+
+
+
+
+
+サーバでは、handlerFuncをひとつ追加します:
+
+ http.HandleFunc("/upload", upload)
+
+ // /uploadを処理するロジック
+ func upload(w http.ResponseWriter, r *http.Request) {
+ fmt.Println("method:", r.Method) //リクエストを受け取るメソッド
+ if r.Method == "GET" {
+ crutime := time.Now().Unix()
+ h := md5.New()
+ io.WriteString(h, strconv.FormatInt(crutime, 10))
+ token := fmt.Sprintf("%x", h.Sum(nil))
+
+ t, _ := template.ParseFiles("upload.gtpl")
+ t.Execute(w, token)
+ } else {
+ r.ParseMultipartForm(32 << 20)
+ file, handler, err := r.FormFile("uploadfile")
+ if err != nil {
+ fmt.Println(err)
+ return
+ }
+ 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)
+ }
+ }
+
+上のコードでは、ファイルのアップロードを処理するためには`r.ParseMultipartForm`をコールする必要があります。引数には`maxMemory`が表示されています。`ParseMultipartForm`をコールした後、アップロードするファイルは`maxMemory`のサイズのメモリに保存されます。もしファイルのサイズが`maxMemory`を超えた場合、残った部分はシステムのテンポラリファイルに保存されます。`r.FormFile`によって上のファイルハンドルを取得することができます。その後実例の中では`io.Copy`を使ってファイルを保存しています。
+
+>その他のファイルではないフィールド情報を取得する時は`r.ParseForm`をコールする必要はありません。必要な時はGoが自動でコールします。また`ParseMultipartFrom`を一度コールすると、その後にもう一度コールしても効果はありません。
+
+上の実例を通して、ファイルのアップロードには主に3ステップの処理があることが分かります:
+
+1. フォームにenctype="multipart/form-data"を追加する。
+2. サーバで`r.ParseMultipartForm`をコールし、アップロードするファイルをメモリとテンポラリファイルに保存する。
+3. `r.FormFile`を使用して、ファイルハンドルを取得し、ファイルに対して保存等の処理を行う。
+
+ファイルhandlerはmultipart.FileHnadlerです。この中には以下のような構造体が保存されています。
+
+ type FileHeader struct {
+ Filename string
+ Header textproto.MIMEHeader
+ // contains filtered or unexported fields
+ }
+
+上のコード例では以下のようにファイルのアップロードを出力します。
+
+
+
+図4.5 ファイルのアップロードを行った後サーバが受け取った情報の出力
+
+## クライアントによるファイルのアップロード
+
+上の例でどのようにフォームからファイルをアップロードするのか示しました。その後サーバでファイルを処理しますが、Goは実はクライアントのフォームによるファイルのアップロードをエミュレートする機能をサポートしています。詳しい仕様方法は以下の例をご覧ください:
+
+ package main
+
+ import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "mime/multipart"
+ "net/http"
+ "os"
+ )
+
+ func postFile(filename string, targetUrl string) error {
+ bodyBuf := &bytes.Buffer{}
+ bodyWriter := multipart.NewWriter(bodyBuf)
+
+ //キーとなる操作
+ fileWriter, err := bodyWriter.CreateFormFile("uploadfile", filename)
+ if err != nil {
+ fmt.Println("error writing to buffer")
+ return err
+ }
+
+ //ファイルハンドル操作をオープンする
+ fh, err := os.Open(filename)
+ if err != nil {
+ fmt.Println("error opening file")
+ return err
+ }
+
+ //iocopy
+ _, err = io.Copy(fileWriter, fh)
+ if err != nil {
+ return err
+ }
+
+ contentType := bodyWriter.FormDataContentType()
+ bodyWriter.Close()
+
+ resp, err := http.Post(targetUrl, contentType, bodyBuf)
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ resp_body, err := ioutil.ReadAll(resp.Body)
+ if err != nil {
+ return err
+ }
+ fmt.Println(resp.Status)
+ fmt.Println(string(resp_body))
+ return nil
+ }
+
+ // sample usage
+ func main() {
+ target_url := "http://localhost:9090/upload"
+ filename := "./astaxie.pdf"
+ postFile(filename, target_url)
+ }
+
+
+上の例ではクライアントが如何にサーバに対し一つのファイルをアップロードするのかご説明しました。クライアントはmultipart.Writeを通してファイルの本文をバッファの中に書き込みます。その後、httpのPostメソッドをコールしてバッファからサーバに転送します。
+
+>もしあなたが他にusernameといった普通のフィールドを同時に書き込む場合は、multipartのWriteFieldメソッドをコールして、その他の似たようなフィールドを複数書き込むことができます。
+
+## links
+ * [目次]()
+ * 前へ: [フォームの多重送信の防止](<04.4.md>)
+ * 次へ: [サマリー](<04.6.md>)
+