3

noob Golang 和 Sinatra 人在这里。我破解了一个 Sinatra 应用程序,以接受从 HTML 表单发布的上传文件,并通过 GridFS 将其保存到托管的 MongoDB 数据库中。这似乎工作正常。我正在使用 mgo 驱动程序在 Golang 中编写相同的应用程序。

从功能上讲,它工作正常。但是在我的 Golang 代码中,我将文件读入内存,然后使用 mgo 将文件从内存写入 MongoDB。这似乎比我的同等 Sinatra 应用程序慢得多。我觉得 Rack 和 Sinatra 之间的交互不会执行这个“中间”或“中间”步骤。

这是我的 Go 代码片段:

func uploadfilePageHandler(w http.ResponseWriter, req *http.Request) {
  // Capture multipart form file information
  file, handler, err := req.FormFile("filename")
  if err != nil {
    fmt.Println(err)
  }

  // Read the file into memory
  data, err := ioutil.ReadAll(file)
  // ... check err value for nil

  // Specify the Mongodb database
  my_db := mongo_session.DB("... database name...")

  // Create the file in the Mongodb Gridfs instance
  my_file, err := my_db.GridFS("fs").Create(unique_filename)
  // ... check err value for nil

  // Write the file to the Mongodb Gridfs instance
  n, err := my_file.Write(data)
  // ... check err value for nil

  // Close the file
  err = my_file.Close()
  // ... check err value for nil

  // Write a log type message
  fmt.Printf("%d bytes written to the Mongodb instance\n", n)

  // ... other statements redirecting to rest of user flow...
}

问题

  • 是否需要这个“临时”步骤(data, err := ioutil.ReadAll(file))?
  • 如果是这样,我可以更有效地执行此步骤吗?
  • 我应该考虑其他公认的做法或方法吗?

谢谢...

4

2 回答 2

9

不,您不应该一次在内存中完全读取文件,因为当文件太大时会中断。GridFS.Create 文档中的第二个示例避免了这个问题:

file, err := db.GridFS("fs").Create("myfile.txt")
check(err)
messages, err := os.Open("/var/log/messages")
check(err)
defer messages.Close()
err = io.Copy(file, messages)
check(err)
err = file.Close()
check(err)

至于为什么它比其他东西慢,如果不深入研究所使用的两种方法的细节就很难说清楚。

于 2014-03-05T14:28:42.577 回答
1

从 multipartForm 获得文件后,可以使用以下函数将其保存到 GridFs 中。我也针对大文件(高达 570MB)进行了测试。

//....code inside the handlerfunc
for _, fileHeaders := range r.MultipartForm.File {
        for _, fileHeader := range fileHeaders {
            file, _ := fileHeader.Open()            
            if gridFile, err := db.GridFS("fs").Create(fileHeader.Filename); err != nil {
                //errorResponse(w, err, http.StatusInternalServerError)
                return
            } else {
                gridFile.SetMeta(fileMetadata)
                gridFile.SetName(fileHeader.Filename)
                if err := writeToGridFile(file, gridFile); err != nil {
                    //errorResponse(w, err, http.StatusInternalServerError)
                    return
                }
func writeToGridFile(file multipart.File, gridFile *mgo.GridFile) error {
    reader := bufio.NewReader(file)
    defer func() { file.Close() }()
    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := reader.Read(buf)
        if err != nil && err != io.EOF {
            return errors.New("Could not read the input file")
        }
        if n == 0 {
            break
        }
        // write a chunk
        if _, err := gridFile.Write(buf[:n]); err != nil {
            return errors.New("Could not write to GridFs for "+ gridFile.Name())
        }
    }
    gridFile.Close()
    return nil
}
于 2015-11-28T20:43:42.323 回答