求获取上传文件大小可能失败的原因(已解决)

// 获取文件大小的接口
type Size interface {
       Size() int64
}

func HelloServer(w http.ResponseWriter, r *http.Request) {
    file, _, _ := r.FormFile("file")   //这里的err一直是nil,所以用"_"

    if sizeInterface, ok := file.(Size); ok { //小文件可以成功;大文件,比如180MB,就无法获取到
           fmt.Fprintf(w, "上传文件的大小为: %d", sizeInterface.Size())
     }
}

求通过 file.(Size)获取文件大小可能失败的原因.

共 12 个回复


jimmykuu

file, _, err := r.FormFile("file") 看看这个 err 是啥,别忽略了。

# 0

brucelandor

在这之前要调用一下r.ParseMultipartForm()

# 1

chenhao

r.FormFile("file")的err都是nil所以就忽略了.

# 2

chenhao

@brucelandor 如果需要func (r *Request) FormFile(key string) 会自动调用ParseMultipartForm的.

# 3

jimmykuu

把完整代码放出来,包括模板的,大家好测试下。

# 5

yufeng

@#4
r.FormFile 确实会自动调用ParseMultipartFrom,但是他是这样调用的

err := r.ParseMultipartForm(defaultMaxMemory)

而这个defaultMaxMemory 默认是32M的

so....

# 7

chenhao

听了别人的建议,加了一句"fmt.Printf("%T\n", file)",发现 type 为 multipart.sectionReadCloser时,可以得到大小 type 为 *os.File(上传大文件)时,得不到大小

咋回事,类型还会变化.

# 8

jimmykuu

func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) 的返回值 multipart.File 是一个 interface ,只要实现这个 interface 里的方法的类型都可以。

估计是上传的小文件数据就放内存了,用了 multipart.sectionReadCloser 结构体存放,而超过一定大小,就存放在临时文件了,因此用 os.File 类型。

判断下类型,然后如果是文件的话用获取文件大小的方式来获取就可以了。

# 9

jimmykuu

看了下源码,是这样的:

type Request struct {
    // ...
    MultipartForm *multipart.Form
    // ...
}

上传数据是放在 multipart.Form 里的,看下 multipart.Form 的定义和文档:

type Form struct {
    Value map[string][]string
    File  map[string][]*FileHeader
}

Form is a parsed multipart form. Its File parts are stored either in memory or on disk, and are accessible via the *FileHeader's Open method. Its Value parts are stored as strings. Both are keyed by field name.

# 10

chenhao

调整后的代码:

// 获取文件大小的接口
type Size interface {
    Size() int64
}
// 获取文件信息的接口
type Stat interface {
    Stat() (os.FileInfo, error)
}
if statInterface, ok := file.(Stat); ok {
    fileInfo, _ := statInterface.Stat()
    fmt.Fprintf(w, "上传文件的大小为: %d", fileInfo.Size())
}
if sizeInterface, ok := file.(Size); ok {
    fmt.Fprintf(w, "上传文件的大小为: %d", sizeInterface.Size())
}
# 11