Baca file biner sebagai string di Ruby


263

Saya perlu cara mudah untuk mengambil file tar dan mengubahnya menjadi string (dan sebaliknya). Apakah ada cara untuk melakukan ini di Ruby? Upaya terbaik saya adalah ini:

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

Saya pikir itu akan cukup untuk mengubahnya menjadi string, tetapi kemudian ketika saya mencoba untuk menulis kembali seperti ini ...

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

Itu bukan file yang sama. Melakukan ls -lmenunjukkan file memiliki ukuran yang berbeda, meskipun mereka cukup dekat (dan membuka file mengungkapkan sebagian besar konten utuh). Apakah ada kesalahan kecil yang saya buat atau cara yang sama sekali berbeda (tapi bisa diterapkan) untuk mencapai ini?


3
Itu file tar yang di-gzip (saya harap). Tidak ada "garis". Tolong jelaskan apa yang ingin Anda capai.
Brent.Longborough

apakah Anda mencoba melihat data terkompresi atau konten yang tidak terkompresi?
David Nehme

jadi karakter dalam aliran data terkompresi akan memiliki peluang kira-kira 1 dalam 256 untuk mendarat di "\ n" mendefinisikan akhir baris, dan tidak apa-apa jika tidak mengharapkan "\ r" juga, lihat jawaban saya di bawah ini
Purfideas

Pertanyaan ini harus diberi judul ulang "Konversi file biner ke string", karena IO.readakan menjadi jawaban yang lebih disukai.
Ian

Jawaban:


397

Pertama, Anda harus membuka file sebagai file biner. Kemudian Anda dapat membaca seluruh file dalam satu perintah.

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

Itu akan membuat Anda seluruh file dalam sebuah string.

Setelah itu, Anda mungkin ingin file.close. Jika Anda tidak melakukan itu, filetidak akan ditutup sampai pengumpulan sampah, jadi itu akan menjadi sedikit pemborosan sumber daya sistem saat terbuka.


22
Bendera biner hanya relevan pada Windows, dan ini membiarkan deskriptor file terbuka. File.read (...) lebih baik.
Daniel Huckstep

Apakah ada yang salah dengan begitu banyak orang mencari ini dan menyalinnya sebagai solusi satu-liner (seperti banyak hal di stackoverflow)? Bagaimanapun, itu berhasil, dan nama untuk fungsi-fungsi ini hanyalah pilihan sewenang-wenang dari perancang perpustakaan ruby. Kalau saja kita memiliki beberapa bahasa dengan sinonim ... yang entah bagaimana masih tahu persis apa yang kita inginkan dalam kasus tepi / contoh ambigu. Maka saya hanya akan contents = (contents of file "path to file.txt" as string).
masterxilo

2
Ini harus dilakukan dalam begin {..open..} ensure {..close..} endblok
shadowbq

3
@ArianFaurtosh Tidak, ini metode lain untuk membaca file - itu tidak berarti akan diperlakukan sebagai exectuable dan dijalankan! Itu akan menjadi efek samping yang mengerikan untuk metode 'membaca' sederhana.
Matius Baca

1
@ David tidak bisa Anda hanya melakukan satu-liner berikut? contents = File.binread('path-to-file.tar.gz')Lihat apidock . Fileadalah subkelas dari IO.
vas

244

Jika Anda memerlukan mode biner, Anda harus melakukannya dengan cara yang sulit:

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

Jika tidak, lebih pendek dan lebih manis adalah:

s = IO.read(filename)

Di ruby ​​1.9.3+, IO.read akan memberi Anda sebuah string yang ditandai dengan penyandian di Encoding.default_external. Saya pikir (?) Byte semua akan seperti yang ada di file, jadi itu bukan "tidak biner-aman", tetapi Anda harus menandainya dengan pengkodean biner jika itu yang Anda inginkan.
jrochkind

Jika kependekan dan kemanisan adalah intisari, trik proc ampersand-symbol memberis = File.open(filename, 'rb', &:read)
Epigene 4'19

114

Untuk menghindari membiarkan file tetap terbuka, yang terbaik adalah meneruskan blok ke File.open. Dengan cara ini, file akan ditutup setelah blok dijalankan.

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

10
Ini adalah jawaban yang lebih baik daripada David Nehme karena file deskriptor adalah sumber daya sistem yang terbatas dan melelahkan mereka adalah masalah umum yang dapat dengan mudah dihindari.
Jeff McCune

17

pada os x ini sama bagi saya ... mungkinkah ini "ekstra" di windows?

dalam hal apa pun Anda mungkin lebih baik dengan:

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

Ini sepertinya solusi paling sederhana.
Dishcandanty


10

Ruby membaca biner

data = IO.binread(path/filaname)

atau jika kurang dari Ruby 1.9.2

data = IO.read(path/file)

7

Anda mungkin bisa menyandikan file tar di Base64. Basis 64 akan memberi Anda representasi ASCII murni dari file yang dapat Anda simpan dalam file teks biasa. Kemudian Anda dapat mengambil file tar dengan mendekode teks kembali.

Anda melakukan sesuatu seperti:

require 'base64'

file_contents = Base64.encode64(tar_file_data)

Lihat di Base64 Rubydocs untuk mendapatkan ide yang lebih baik.


Hebat, ini sepertinya akan bekerja juga! Saya harus memeriksanya jika karena alasan tertentu membaca konten biner menjadi masam.
Chris Bunch

0

Jika Anda dapat menyandikan file tar dengan Base64 (dan menyimpannya dalam file teks biasa) yang dapat Anda gunakan

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

atau

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

untuk mencetak setiap baris (teks) dalam cmd.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.