2016-04-27 91 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