go - 使用 part.Read 每 block 读取超过 4096 字节

标签 go

我正在尝试以小块的形式处理多部分文件上传,以避免将整个文件存储在内存中。下面的函数似乎解决了这个问题,但是当传递一个 []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/

相关文章:

json - Go json.Unmarshal() 适用于单个实体但不适用于 slice

golang将fasthttp替换为gin, slice 边界超出范围运行时错误

go - 在 Go 中使用 fmt.Printf 打印多个内容

go - 带有接口(interface)参数的函数不等于带有字符串参数的函数。为什么?

go - 在 Go 中创建单向 channel 有什么意义

go - 无法使用带有 BurntSushi 库的 Go 读取 TOML 文件

net 包中的 Golang 类型

go - 有没有办法访问结构字段之类的接口(interface)或使用相同字段更改类型(不同结构)

go - 使用 golang 将 DateTime 值插入 MS SQL

go - 如何在 Golang 中将 multipart.File 类型转换为 *os.File