2016-04-27 90 views
2
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保存到文件做一些检查:如何添加文件(io.Reader)?

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

你正在测试这个文件的大小是多少?你似乎没有检查有多少字节被读入缓冲区,或者如果在执行'file.Read(buf)'时返回任何错误' –

+0

我正在测试一个200 MB的文件。我已删除所有错误检查以缩短问题。这一步没有错误。 – Monodeep

+0

我会第二个Dean的评论。仅仅因为没有错误并不意味着你的缓冲区充满了读者的数据。你永远不能认为在一个流上读取的内容会填充这么大的缓冲区。其次,虽然ioutil功能很不错,你可以很容易地只写使用文件的io.Writer接口,并在必要时使用SEEK()上的文件来调整写入位置。 –

回答

1

你已经基本上做os.Create和ioutil.WriteFile

问题的存在是os.Create的返回值(DST)就像是一个指向文件的开头打开的文件的两倍。 WriteFile不会在dst指向的位置移动。

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

尝试首先执行WriteFile(使用Create标志),然后使用Append标志将os.OpenFile(而不是os.Create)添加到具有Append标志的同一文件中,以便将其余字节附加到末尾。

此外,允许客户端为您提供文件名是非常危险的,因为它可能是../../.bashrc(例如),您可以用任何用户决定覆盖您的shell init上传。

这将是更安全的,如果你自己计算的文件名,如果你需要记住用户选择的文件名,在您的数据库,甚至一个metadata.json类型的文件,你以后装入存储。

+0

作为建议我这样做:' ioutil.WriteFile(tempFile,buf,0644)'then'dst,err:= os.OpenFile(tempFile,os.O_RDWR | os.O_APPEND,0666) \t defer dst.Close() \t _,err = io。复制(dst,file)'仍然文件大小增加1mb并损坏。 – Monodeep