2014-04-09 16 views
6

Tôi đang viết một máy chủ web khi đang di chuyển.http Request.FormFile: xử lý các tệp zip?

Trên một trong các trang, người dùng có thể tải lên tệp.

Tôi muốn có thể xử lý các tệp zip.

Trong gói archive/zip, tôi chỉ nhìn thấy hai chức năng đó cho phép tôi để đọc từ một kho lưu trữ zip:

  1. func OpenReader(name string) (*ReadCloser, error)
  2. func NewReader(r io.ReaderAt, size int64) (*Reader, error)

tôi muốn tránh bằng văn bản và đọc lại từ đĩa,
nếu tôi muốn sử dụng chức năng thứ hai, tôi cần biết kích thước tệp đã tải lên trước khi gọi hàm.

Câu hỏi

tôi sẽ chia câu hỏi của tôi trong hai phần:

  1. Điều gì sẽ là cách thành ngữ để đọc nội dung đã được giải nén của một tập tin zip tải lên thông qua một hình thức multipart/form-data html tiêu chuẩn?

  2. Làm cách nào tôi có thể nhận được kích thước thực tế của tệp được tải lên thông qua biểu mẫu html?

    func(req *http.Request) { 
        f, h, err := req.FormFile("fileTag") 
        if err != nil { 
         panic(err) 
        } 
        var fileSize int = ?? 
    
        unzipper, err := zip.NewReader(f, fileSize) 
    } 
    

Trả lời

2

Đây là một cách tôi tìm thấy để có được kích thước:

func(req *http.Request) { 
    f, h, err := req.FormFile("fileTag") 
    if err != nil { 
     panic(err) 
    } 
    fileSize, err := f.Seek(0, 2) //2 = from end 
    if err != nil { 
     panic(err) 
    } 
    _, err = f.Seek(0, 0) 
    if err != nil { 
     panic(err) 
    } 

    unzipper, err := zip.NewReader(f, fileSize) 
} 

tôi không tìm thấy giải pháp này rất thanh lịch hoặc thành ngữ.

Không còn cách nào khác để xử lý trường hợp này?

+0

giải pháp mime-header từ câu trả lời của tôi không hoạt động? Nếu bạn đang thiếu một nội dung dài, giải pháp này thực sự rất tốt, vì tôi không nghĩ rằng có một cách để có được nó vào một bộ đệm mà không có ít nhất một bản sao nữa. – JimB

2

Bạn có thể tìm kiếm kích thước tập tin vào những FormFile Header (mà là một MIMEHEader).

h.Header.Get("Content-Length") 

Nếu không có độ dài nội dung cho tệp, bạn có thể đọc nó vào bộ đệm trước để lấy kích thước.

var buff bytes.Buffer 
fileSize, err := buff.ReadFrom(f) 

Các tùy chọn khác là tìm cách kết thúc, khi bạn đưa ra câu trả lời hoặc đưa Reader ra khỏi giao diện. Một tập tin nhiều phần dữ liệu sẽ là một *io.SectionReader nếu nó trong bộ nhớ, hoặc một *os.File nếu nó được viết vào một tập tin tạm thời:

switch f := f.(type) { 
case *io.SectionReader: 
    fileSize = r.Size() 
case *os.File: 
    if s, err := f.Stat(); err == nil { 
     fileSize = s.Size() 
    } 
} 
+0

Không 'Content-Length' trong tiêu đề ... Tuy nhiên, 'Content-Length' sẽ là giá trị của tiêu đề được viết bởi khách hàng, phải không? – LeGEC

+0

có, đó là tiêu đề ở dạng nhiều phần (* không * tiêu đề yêu cầu http), vì vậy nó sẽ phải được gửi bởi khách hàng. – JimB

+0

Cảm ơn đề xuất SectionReader. Thật không may, f có thể là một SectionReader, hoặc một os.File. Xem [mã cho FileHeader.Open] (http://golang.org/src/pkg/mime/multipart/formdata.go?s=2942:2984#L121) – LeGEC

1

Tôi sẽ sử dụng một bộ đệm trong bộ nhớ và chắc chắn để hạn chế kích thước tải lên tối đa của một tập tin (~ 100MB?) Ở đây nó được sử dụng io.Copy

import (
    "archive/zip" 
    "bytes" 
    "io" 
    "net/http" 
) 

func HttHandler(req *http.Request) { 

    f, _, err := req.FormFile("fileTag") 

    if err != nil { 
     panic(err) 
    } 

    buf := new(bytes.Buffer) 

    fileSize, err := io.Copy(buf, f) 
    if err != nil { 
     panic(err) 
    } 

    zip.NewReader(bytes.NewReader(buf.Bytes()), fileSize) 

} 
Các vấn đề liên quan