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

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)
}

I am uploading a Video file. Before uploading the entire file I want to do some checks so I save the first 1mb to a file :

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

Then if the checks pass I want to upload the rest of the file dst is the same file used to save the 1st 1 mb so basically i am trying to append to the file :

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

The uploaded file size is correct but the file is corrupted(can't play the video).

What else have I tried? : Joining both the readers and saving to a new file. But with this approach the file size increases by 1 mb and is corrupted.

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

Kindly help.

You've basically opened the file twice by doing os.Create and ioutil.WriteFile

the issue being is that os.Create's return value (dst) is like a pointer to the beginning of that file. WriteFile doesn't move where dst points to.

You are basically doing WriteFile, then io.Copy on top of the first set of bytes WriteFile wrote.

Try doing WriteFile first (with Create flag), and then os.OpenFile (instead of os.Create) that same file with Append flag to append the remaining bytes to the end.

Also, it's extremely risky to allow a client to give you the filename as it could be ../../.bashrc (for example), to which you'd overwrite your shell init with whatever the user decided to upload.

It would be much safer if you computed a filename yourself, and if you need to remember the user's selected filename, store that in your database or even a metadata.json type file that you load later.