Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

golang - How to check multipart.File information

Tags:

file-upload

go

When a user uploads a file, using r.FormFile("file") you get a multipart.File, a multipart.FileHeader and an error.

My question is how to just obtain information about the uploaded file for example, it's size, and if it's an image it's demensions, and so on and so forth.

I have literally got no idea on where to start so any help would be great.

like image 455
user81779 Avatar asked Jun 16 '13 03:06

user81779


4 Answers

To get the file size and MIME type:

// Size constants
const (
        MB = 1 << 20
)

type Sizer interface {
        Size() int64
}

func Sample(w http.ResponseWriter, r *http.Request) error {
        if err := r.ParseMultipartForm(5 * MB); err != nil {
                return err
        }

        // Limit upload size
        r.Body = http.MaxBytesReader(w, r.Body, 5*MB) // 5 Mb

        //
        file, multipartFileHeader, err := r.FormFile("file")

        // Create a buffer to store the header of the file in
        fileHeader := make([]byte, 512)

        // Copy the headers into the FileHeader buffer
        if _, err := file.Read(fileHeader); err != nil {
                return err
        }

        // set position back to start.
        if _, err := file.Seek(0, 0); err != nil {
                return err
        }

        log.Printf("Name: %#v\n", multipartFileHeader.Filename)
        log.Printf("Size: %#v\n", file.(Sizer).Size())
        log.Printf("MIME: %#v\n", http.DetectContentType(fileHeader))
}

Sample output:

2016/12/01 15:00:06 Name: "logo_35x30_black.png"
2016/12/01 15:00:06 Size: 18674
2016/12/01 15:00:06 MIME: "image/png"
like image 193
Jun Hsieh Avatar answered Oct 24 '22 06:10

Jun Hsieh


Another way I've found pretty simple for this type of testing is to place test assets in a test_data directory relative to the package. Within my test file I normally create a helper that creates an instance of *http.Request, which allows me to run table test pretty easily on multipart.File, (errors checking removed for brevity).

func createMockRequest(pathToFile string) *http.Request {
    file, err := os.Open(pathToFile)
    if err != nil {
        return nil
    }
    defer file.Close()

    body := &bytes.Buffer{}
    writer := multipart.NewWriter(body)
    part, err := writer.CreateFormFile("file", filepath.Base(pathToFile))
    if err != nil {
        return nil
    }
    _, _ = io.Copy(part, file)

    err = writer.Close()
    if err != nil {
        return nil
    }
    // the body is the only important data for creating a new request with the form data attached
    req, _ := http.NewRequest("POST", "", body)
    req.Header.Set("Content-Type", writer.FormDataContentType())
    return req
}
like image 38
reticentroot Avatar answered Oct 24 '22 05:10

reticentroot


The file name and MIME type can be obtained from the returned multipart.FileHeader.

Most further meta-data will depend on the file type. If it's an image, you should be able to use the DecodeConfig functions in the standard library, for PNG, JPEG and GIF, to obtain the dimensions (and color model).

There are many Go libraries available for other file types as well, which will have similar functions.

EDIT: There's a good example on the golang-nuts mail group.

like image 40
Intermernet Avatar answered Oct 24 '22 04:10

Intermernet


You can get approximate information about the size of file from Content-Length header. This is not recommended, because this header can be changed.

A better way is to use ReadFrom method:

clientFile, handler, err := r.FormFile("file") // r is *http.Request
var buff bytes.Buffer
fileSize, err := buff.ReadFrom(clientFile)
fmt.Println(fileSize) // this will return you a file size.
like image 45
Salvador Dali Avatar answered Oct 24 '22 05:10

Salvador Dali