Automatically open a file as binary with Ruby
Actually, the previous answer by Alex D is incomplete. While it's true that there is no "text" mode in Unix file systems, Ruby does make a difference between opening files in binary and non-binary mode:
s = File.open('/tmp/test.jpg', 'r') { |io| io.read }
s.encoding
=> #<Encoding:UTF-8>
is different from (note the "rb"
)
s = File.open('/tmp/test.jpg', 'rb') { |io| io.read }
s.encoding
=> #<Encoding:ASCII-8BIT>
The latter, as the docs say, set the external encoding to ASCII-8BIT which tells Ruby to not attempt to interpret the result at UTF-8. You can achieve the same thing by setting the encoding explicitly with s.force_encoding('ASCII-8BIT')
. This is key if you want to read binary into a string and move them around (e.g. saving them to a database, etc.).
Opening file in binary mode and saving it adds new line
I ran some tests; it depends on the way your lines end. When they end with either LF
(\n
) or CR
(\r
) it will produce output like you expect. That is, no new lines are added. However, if you have CRLF
(\r\n
) it will add a CR
character after each line, thus ending it effectively with CRCR+LF
which produces the extra line.
Most programming editors allow you to select an option which makes the line endings visible.
I am not exactly sure why this happens, but likely has to do with the following snippet from the IO docs at the 'b'
mode:
Suppresses EOL <-> CRLF conversion on Windows.
It appears that when not using binary mode, CRLF (default end-of-lines on Windows) are converted to LF's. The simple solution thus seems to just replace all \r\n
by either \n
or \r
. You can do that like this:
File.open('converted.txt', 'wb') do |converted|
File.open('1.txt', 'rb').each_line do |line|
converted << line.gsub("\r\n", "\n") # Replace CRLF with LF
end
end
If you run the script multiple times on the same file, you should make sure to replace CRLF with LF before you write it back:
# Note the .gsub at the end here
text = File.read('1.txt', mode: 'rb', encoding: 'UTF-8').gsub("\r\n", "\n")
File.write('1.txt', text, encoding: 'UTF-8')
Read binary file as string in Ruby
First, you should open the file as a binary file. Then you can read the entire file in, in one command.
file = File.open("path-to-file.tar.gz", "rb")
contents = file.read
That will get you the entire file in a string.
After that, you probably want to file.close
. If you don’t do that, file
won’t be closed until it is garbage-collected, so it would be a slight waste of system resources while it is open.
How to write a Tempfile as binary
Tempfile.new
passes options to File.open
which accepts the options from IO.new
, in particular:
:binmode
If the value is truth value, same as “b” in argumentmode
.
So to open a tempfile in binary mode, you'd use:
temp_file = Tempfile.new([name, extension], binmode: true)
temp_file.binmode? #=> true
temp_file.external_encoding #=> #<Encoding:ASCII-8BIT>
In addition, you might want to use Tempfile.create
which takes a block and automatically closes and removes the file afterwards:
Tempfile.create([name, extension], binmode: true) do |temp_file|
temp_file.write(unzipped_io.read)
# ...
end
Ruby: How to convert a string to binary and write it to file
Try using double quotes:
data = "BZh91AY&SY\x94$|\x0e\x00\x00\x00\x81\x00\x03"
Then do as sepp2k suggested.
Java - reading file as binary with readLine
You can use java.io.DataInputStream
which provides both a readLine()
method and readFully(byte[])
and read(byte[])
methods.
Warning: The JavaDoc for readLine
says, it is deprecated and that the encoding might be inappropriate (read details in JavaDoc).
So think twice about your real requirements and if this is a suitable trade-off in your case.
How do I download a binary file over HTTP?
The simplest way is the platform-specific solution:
#!/usr/bin/env ruby
`wget http://somedomain.net/flv/sample/sample.flv`
Probably you are searching for:
require 'net/http'
# Must be somedomain.net instead of somedomain.net/, otherwise, it will throw exception.
Net::HTTP.start("somedomain.net") do |http|
resp = http.get("/flv/sample/sample.flv")
open("sample.flv", "wb") do |file|
file.write(resp.body)
end
end
puts "Done."
Edit: Changed. Thank You.
Edit2: The solution which saves part of a file while downloading:
# instead of http.get
f = open('sample.flv')
begin
http.request_get('/sample.flv') do |resp|
resp.read_body do |segment|
f.write(segment)
end
end
ensure
f.close()
end
Related Topics
Ruby Interactive Shell Commands
Does the Order of Gems in Your Gemfile Make a Difference
Handling Iframe with Capybara Ruby
Can "Gem Install" Be Configured to Install Executables Outside /Usr/Bin/ by Default
How to Preserve Case with Http.Get
What Can a Ruby Symbol (Syntax) Contain
Failure: Expected 0 to Be >= 1 on Ruby on Rails
"Msvcrt-Ruby18.Dll Was Not Found" with Ruby
If(!X) VS If(X==False) in Ruby
How to Read Files in an Eventmachine-Based App
Mailchimp API Not Replacing Mc:Edit Content Sections (Using Ruby Library)
In Ruby How to Use Class Level Local Variable? (A Ruby Newbie's Question)