如何附加文件(io.Reader)?

时间:2016-04-27 16:31:04

标签: go

func SimpleUploader(r *http.Request, w http.ResponseWriter) {
    // temp folder path
    chunkDirPath := "./creatives/.uploads/" + userUUID
    // create folder
    err = os.MkdirAll(chunkDirPath, 02750)

    // Get file handle from multipart request
    var file io.Reader
    mr, err := r.MultipartReader()

    var fileName string
    // Read multipart body until the "file" part
    for {
        part, err := mr.NextPart()
        if err == io.EOF {
            break
        }
        if part.FormName() == "file" {
            file = part
            fileName = part.FileName()
            fmt.Println(fileName)
            break
        }
    }

    // Create files
    tempFile := chunkDirPath + "/" + fileName
    dst, err := os.Create(tempFile)

    defer dst.Close()

    buf := make([]byte, 1024*1024)
    file.Read(buf)
    // write/save buffer to disk
    ioutil.WriteFile(tempFile, buf, os.ModeAppend)
    if http.DetectContentType(buf) != "video/mp4" {
        response, _ := json.Marshal(&Response{"File upload cancelled"})
        settings.WriteResponse(w, http.StatusInternalServerError, response)
        return
    }

    // joinedFile := io.MultiReader(bytes.NewReader(buf), file)
    _, err = io.Copy(dst, file)
    if err != nil {
        settings.LogError(err, methodName, "Error copying file")
    }

    response, _ := json.Marshal(&Response{"File uploaded successfully"})
    settings.WriteResponse(w, http.StatusInternalServerError, response)
}

我正在上传视频文件。 在上传整个文件之前,我想做一些检查,所以我将第一个1mb保存到文件中:

buf := make([]byte, 1024*1024)
file.Read(buf)
// write/save buffer to disk
ioutil.WriteFile(tempFile, buf, os.ModeAppend)

然后,如果检查通过,我想上传文件的其余部分dst is the same file used to save the 1st 1 mb,所以基本上我试图附加到文件:

_, err = io.Copy(dst, file)

上传的文件大小正确但文件已损坏(无法播放视频)。

我还尝试了什么? :加入读者并保存到新文件。但是使用这种方法,文件大小增加了1 MB并且已损坏。

joinedFile := io.MultiReader(bytes.NewReader(buf), file)
_, err = io.Copy(newDst, joinedFile)

请帮助。

1 个答案:

答案 0 :(得分:1)

你通过os.Create和ioutil.WriteFile基本上打开了两次文件

问题是os.Create的返回值(dst)就像是指向该文件开头的指针。 WriteFile不会在dst指向的位置移动。

你基本上是在写WriteFile,然后是在第一组字节WriteFile写的顶部的io.Copy。

首先尝试使用WriteFile(使用Create标志),然后尝试使用Append标记的os.OpenFile(而不是os.Create)将剩余的字节追加到末尾。

此外,允许客户端为您提供文件名是极其危险的,因为它可能是../../.bashrc(例如),您要用它覆盖shell init无论用户决定上传什么。

如果您自己计算文件名会更安全,并且如果您需要记住用户选择的文件名,请将其存储在数据库中,或者甚至存储在稍后加载的metadata.json类型文件中。