Đọc tệp nhị phân dưới dạng chuỗi trong Ruby


263

Tôi cần một cách dễ dàng để lấy một tập tin tar và chuyển đổi nó thành một chuỗi (và ngược lại). Có cách nào để làm điều này trong Ruby? Nỗ lực tốt nhất của tôi là thế này:

file = File.open("path-to-file.tar.gz")
contents = ""
file.each {|line|
  contents << line
}

Tôi nghĩ rằng nó sẽ đủ để chuyển đổi nó thành một chuỗi, nhưng sau đó khi tôi cố gắng viết nó ra như thế này ...

newFile = File.open("test.tar.gz", "w")
newFile.write(contents)

Nó không phải là cùng một tập tin. Việc ls -lhiển thị các tệp có kích thước khác nhau, mặc dù chúng khá gần (và việc mở tệp cho thấy hầu hết các nội dung còn nguyên vẹn). Có một lỗi nhỏ tôi đang mắc phải hoặc một cách hoàn toàn khác (nhưng hoàn toàn khả thi) để thực hiện điều này?


3
Đó là một tập tin tar được nén (tôi hy vọng). Không có "dòng". Xin làm rõ những gì bạn đang cố gắng để đạt được.
Brent.Longborough

bạn đang cố gắng xem xét dữ liệu nén hoặc nội dung không nén?
David Nehme

vì vậy, các ký tự trong luồng dữ liệu nén sẽ có khoảng 1 trong 256 cơ hội hạ cánh trên "\ n" xác định cuối dòng và cũng không sao nếu nó không mong đợi "\ r", hãy xem câu trả lời của tôi dưới đây
Purfideas

Câu hỏi này nên được đặt lại tên là "Chuyển đổi tệp nhị phân thành chuỗi", vì IO.readsẽ là câu trả lời ưa thích khác.
Ian

Câu trả lời:


397

Đầu tiên, bạn nên mở tệp dưới dạng tệp nhị phân. Sau đó, bạn có thể đọc toàn bộ tệp trong một lệnh.

file = File.open("path-to-file.tar.gz", "rb")
contents = file.read

Điều đó sẽ giúp bạn có được toàn bộ tập tin trong một chuỗi.

Sau đó, bạn có thể muốn file.close. Nếu bạn không làm điều đó, filesẽ không bị đóng cửa cho đến khi nó được thu gom rác, vì vậy nó sẽ gây lãng phí một chút tài nguyên hệ thống trong khi nó đang mở.


22
Cờ nhị phân chỉ có liên quan trên Windows và điều này làm cho bộ mô tả tệp mở. File.read (...) là tốt hơn.
Daniel Huckstep

Có điều gì sai trái với rất nhiều người tìm kiếm và sao chép nó như là một giải pháp một lớp (giống như rất nhiều thứ trên stackoverflow)? Rốt cuộc, nó hoạt động, và tên cho các chức năng này chỉ là một sự lựa chọn tùy ý của các nhà thiết kế thư viện ruby. Nếu chỉ có chúng tôi có một số ngôn ngữ với các từ đồng nghĩa ... mà vẫn bằng cách nào đó biết chính xác những gì chúng tôi muốn trong các trường hợp cạnh / trường hợp mơ hồ. Sau đó tôi sẽ chỉcontents = (contents of file "path to file.txt" as string) .
masterxilo

2
Điều này nên được thực hiện trong begin {..open..} ensure {..close..} endcác khối
Shadowbq

3
@ArianFaurtosh Không, đó là một phương pháp đọc tệp khác - điều đó không có nghĩa là nó sẽ được coi là một ngoại lệ và chạy! Đó sẽ là một tác dụng phụ kinh hoàng cho phương pháp 'đọc' đơn giản.
Matthew đã đọc

1
@David bạn không thể đơn giản làm một lớp lót sau đây? contents = File.binread('path-to-file.tar.gz')Xem apidock . Filelà một lớp con của IO.
vas

244

Nếu bạn cần chế độ nhị phân, bạn sẽ cần thực hiện theo cách khó khăn:

s = File.open(filename, 'rb') { |f| f.read }

Nếu không, ngắn hơn và ngọt ngào hơn là:

s = IO.read(filename)

Trong ruby ​​1.9.3+, IO.read sẽ cung cấp cho bạn một chuỗi được đánh dấu bằng mã hóa trong Encoding.default_external. Tôi nghĩ rằng (?) Các byte sẽ giống như trong tệp, vì vậy nó không chính xác là "không an toàn nhị phân", nhưng bạn sẽ phải gắn thẻ nó với mã hóa nhị phân nếu đó là những gì bạn muốn.
jrochkind

Nếu sự ngắn gọn và ngọt ngào là điều cốt yếu, thì trò lừa của biểu tượng ampersand mang lạis = File.open(filename, 'rb', &:read)
Epigene

114

Để tránh để tệp mở, tốt nhất là truyền một khối cho File.open. Bằng cách này, tệp sẽ được đóng lại sau khi khối thực thi.

contents = File.open('path-to-file.tar.gz', 'rb') { |f| f.read }

10
Đây là một câu trả lời tốt hơn David Nehme vì các mô tả tệp là một tài nguyên hệ thống hữu hạn và làm cạn kiệt chúng là một vấn đề phổ biến có thể dễ dàng tránh được.
Jeff McCune

17

trên os x những cái này giống nhau đối với tôi ... điều này có thể là thêm "\ r" trong windows không?

trong mọi trường hợp bạn có thể tốt hơn với:

contents = File.read("e.tgz")
newFile = File.open("ee.tgz", "w")
newFile.write(contents)

Đây dường như là giải pháp đơn giản nhất.
Món ăn

17

làm thế nào về một số an toàn mở / đóng.

string = File.open('file.txt', 'rb') { |file| file.read }

Tại sao không phải là .close rõ ràng? Chẳng hạn như trong tập tin OP. Đóng khi hoàn thành?
Joshua

2
File.open () {| tệp | khối} tự động đóng khi khối kết thúc. ruby-doc.org/core-1.9.3/File.html#method-c-open
Alex

14
Điều này giống hệt với câu trả lời của Aaron Hinni đã được đăng vào năm 2008 (ngoại trừ việc không sử dụng tệp và tên biến của OP) ...
Abe Voelker

10

Ruby có đọc nhị phân

data = IO.binread(path/filaname)

hoặc nếu ít hơn Ruby 1.9.2

data = IO.read(path/file)

7

Bạn có thể mã hóa tệp tar trong Base64. Cơ sở 64 sẽ cung cấp cho bạn bản trình bày ASCII thuần túy của tệp mà bạn có thể lưu trữ trong tệp văn bản thuần túy. Sau đó, bạn có thể truy xuất tệp tar bằng cách giải mã văn bản trở lại.

Bạn làm một cái gì đó như:

require 'base64'

file_contents = Base64.encode64(tar_file_data)

Hãy nhìn vào Base64 Rubydocs để có ý tưởng tốt hơn.


Tuyệt, có vẻ như nó cũng sẽ hoạt động! Tôi sẽ phải kiểm tra xem nếu vì lý do nào đó, việc đọc nội dung nhị phân trở nên tồi tệ.
Chris Bunch

0

Nếu bạn có thể mã hóa tệp tar bằng Base64 (và lưu trữ tệp đó trong tệp văn bản thuần túy), bạn có thể sử dụng

File.open("my_tar.txt").each {|line| puts line}

hoặc là

File.new("name_file.txt", "r").each {|line| puts line}

để in từng dòng (văn bản) trong cmd.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.