我正在尝试以小块的形式处理多部分文件上传,以避免将整个文件存储在内存中。下面的函数似乎解决了这个问题,但是当传递一个 []byte
作为 part.Read()
方法的目标时,它以 4096 字节的 block 读取部分而不是目标大小的 block (len([]byte)
)。
当打开本地文件并将其Read()
'ing 为相同大小的[]byte
时,它会按预期使用整个可用空间。因此我认为它是特定于 part.Reader()
的东西。但是,我无法找到有关该函数的默认大小或最大大小的任何信息。
供引用,函数如下:
func ReceiveFile(w http.ResponseWriter, r *http.Request) {
reader, err := r.MultipartReader()
if err != nil {
panic(err)
}
if reader == nil {
panic("Wrong media type")
}
buf := make([]byte, 16384)
fmt.Println(len(buf))
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
var n int
for {
n, err = part.Read(buf)
if err == io.EOF {
break
}
if err != nil {
panic(err)
}
fmt.Printf("Read %d bytes into buf\n", n)
fmt.Println(len(buf))
}
n, err = part.Read(buf)
fmt.Printf("Finally read %d bytes into buf\n", n)
fmt.Println(len(buf))
}
最佳答案
部分阅读器不会按照 io.Reader 允许的那样尝试填充调用者的缓冲区契约(Contract)。
处理此问题的最佳方法取决于应用程序的要求。
如果你想把这个部分存入内存,那么使用 ioutil.ReadAll :
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
if err != nil {
// handle error
}
p, err := ioutil.ReadAll(part)
if err != nil {
// handle error
}
// p is []byte with the contents of the part
}
如果你想复制部分到io.Writer w
,那么使用io.Copy :
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
if err != nil {
// handle error
}
w := // open a writer
_, err := io.Copy(w, part)
if err != nil {
// handle error
}
}
如果你想处理固定大小的 block ,那么使用io.ReadFull :
buf := make([]byte, chunkSize)
for {
part, err := reader.NextPart()
if err == io.EOF {
break
}
if err != nil {
// handle error
}
_, err := io.ReadFull(part, buf)
if err != nil {
// handle error
// Note that ReadFull returns an error if it cannot fill buf
}
// process the next chunk in buf
}
如果应用程序数据的结构不是固定大小的 block ,那么 bufio.Scanner可能会有帮助。
关于go - 使用 part.Read 每 block 读取超过 4096 字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48644694/