Skip to content

Instantly share code, notes, and snippets.

@HirbodBehnam
Last active November 24, 2021 02:43
Show Gist options
  • Select an option

  • Save HirbodBehnam/d0344f2377cbcd96bc058f31360a7658 to your computer and use it in GitHub Desktop.

Select an option

Save HirbodBehnam/d0344f2377cbcd96bc058f31360a7658 to your computer and use it in GitHub Desktop.
A code to upload multiple files with multipart with small ram usage
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"os"
)
func main() {
url := "https://postman-echo.com/post" // https://docs.postman-echo.com/?version=latest
params := make(map[string]string)
params["test1"] = "param1"
params["test2"] = "param2"
filename1_field := "file1"
filename1 := "test.txt"
filename2_field := "file2"
filename2 := "file2.txt" // however this file will not be read from disk
dataToSend := []byte("Hello!") // insted, send this from memory
r, w := io.Pipe() // use pipe to transfer the data without high RAM usage
m := multipart.NewWriter(w) // create a multipart structure that will use io.Pipe to write to http request
// writing to pipe must be done inside a goroutine; otherwise the program will panic because of deadlock
go func() {
defer w.Close() // you have to at first close the multipart then the pipe
defer m.Close() // note that this line runes first
// write parameters
for k, v := range params {
_ = m.WriteField(k, v)
}
// send the first file that is present on the disk
part, err := m.CreateFormFile(filename1_field, filename1)
if err != nil{
log.Fatal(err)
}
file1, _ := os.Open(filename1) // open the file to read from it
io.Copy(part,file1) // copy the file to multipart; The multipart will use io.pipe to write them to the destination; No worries about the RAM, the buffer size is 32KB
file1.Close()
// now upload the second file from memory
part2, err := m.CreateFormFile(filename2_field, filename2)
if err != nil{
log.Fatal(err)
}
io.Copy(part2,bytes.NewReader(dataToSend))
}()
req, _ := http.NewRequest("POST", url, r) // as you can see I have passed the pipe reader here
req.Header.Set("Content-Type", m.FormDataContentType())
resp, err := http.DefaultClient.Do(req) // do the request. The program will stop here until the upload is done
if err != nil{
log.Fatal(err)
}
data,_ := ioutil.ReadAll(resp.Body) // read the results
fmt.Println(string(data)) // display the results
}
@wellmoon

Copy link
Copy Markdown

๐Ÿ‘

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment