2010-07-02 39 views
7

Tôi có tệp .gz chứa tài liệu XML. Có ai biết cách sử dụng Zlib đúng cách không? Cho đến nay, tôi có đoạn mã sau:Zlib trong Ruby để giải nén .gz

require 'zlib' 
Zlib::GzipReader.open('PRIDE_Exp_Complete_Ac_1015.xml.gz') { |gz| 
    g = File.new("PRIDE_Exp_Complete_Ac_1015.xml", "w") 
     g.write(gz) 
     g.close() 
} 

Nhưng điều này tạo ra một tài liệu .xml trống. Có ai biết làm thế nào tôi có thể làm điều này đúng cách?

Trả lời

22

Zlib::GzipReader hoạt động giống như hầu hết các lớp giống như IO giống như trong Ruby. Bạn có một cuộc gọi open và khi bạn chuyển một khối cho nó, khối sẽ nhận được đối tượng giống như IO. Hãy suy nghĩ về nó là cách thuận tiện để làm một cái gì đó với một tập tin hoặc tài nguyên trong suốt thời gian của khối.

Nhưng điều đó có nghĩa là trong ví dụ gz của bạn là một đối tượng giống như IO và không thực sự là nội dung của tệp gzip, như bạn mong đợi. Bạn vẫn cần phải read để thực hiện điều đó. Việc sửa chữa đơn giản nhất sau đó sẽ là:

g.write(gz.read) 

Lưu ý rằng điều này sẽ đọc toàn bộ nội dung của nén gzip vào bộ nhớ.

Nếu tất cả những gì bạn thực sự đang làm là sao chép từ tệp này sang tệp khác, bạn có thể sử dụng phương thức IO.copy_stream hiệu quả hơn. Ví dụ của bạn có thể trông giống như sau:

Zlib::GzipReader.open('PRIDE_Exp_Complete_Ac_1015.xml.gz') do | input_stream | 
    File.open("PRIDE_Exp_Complete_Ac_1015.xml", "w") do |output_stream| 
    IO.copy_stream(input_stream, output_stream) 
    end 
end 

Phía sau hậu trường, điều này sẽ cố gắng sử dụng syscall sendfile có sẵn trong một số tình huống cụ thể trên Linux. Nếu không, nó sẽ thực hiện sao chép trong các khối mã 16KB mã C nhanh tại một thời điểm. Điều này tôi đã học được từ mã nguồn Ruby 1.9.1.

2

Dưới đây là một Ruby one-liner (cd .git/đầu tiên và xác định đường dẫn đến bất kỳ đối tượng):

ruby -rzlib -e 'print Zlib::Inflate.new.inflate(STDIN.read)' < ./74/c757240ec596063af8cd273ebd9f67073e1208 
Các vấn đề liên quan