Bug #16737
closedFile::BINARY doesn't work
Description
File.open
takes a mode
argument which can be given as a string or as an integer using File::Constants
.
When using the latter, the constant File::BINARY
doesn't have any effect:
# this works:
File.open('foo', 'wb') do |f|
p f.binmode?
p f.external_encoding
end
#=> true
#=> #<Encoding:ASCII-8BIT>
# this doesn't:
File.open('foo', File::WRONLY|File::TRUNC|File::CREAT|File::BINARY) do |f|
p f.binmode?
p f.external_encoding
end
#=> false
#=> nil
Further inspecting File::BINARY
reveals that it has a value of zero:
File::BINARY #=> 0
So it's no surprise that OR-ing it doesn't do anything.
I've tried various Ruby versions from 1.9.3 to 2.7.0 and all showed the above behavior. (I'm on macOS if that matters)
I'm aware that I can achieve the desired result by using a string mode or by passing binary: true
. But since Ruby accepts mode
to be given as an integer, there should be a (working) "b" equivalent.
Updated by nobu (Nobuyoshi Nakada) over 4 years ago
Binary mode makes sense only on Windows.
Just ignore it.
Updated by sawa (Tsuyoshi Sawada) over 4 years ago
It's rather misleading to get f.binmode? #=> true
and f.external_encoding #=> #<Encoding:ASCII-8BIT>
with 'wb'
on unix-family OS.
Updated by jeremyevans0 (Jeremy Evans) over 4 years ago
I agree with @nobu (Nobuyoshi Nakada) that this isn't a bug on !Windows. The documentation for File::Constants::BINARY
states "disable line code conversion", nothing about setting binary mode. I guess the constant name is a bit misleading, but due to backwards compatibility, we cannot change it.
The File::BINARY
behavior on Windows is definitely a bug, as #binmode?
is true but binary external encoding is not set. Calling #binmode
on the file does set the binary external encoding:
f = File.open('a', File::WRONLY|File::TRUNC|File::CREAT|File::BINARY)
# => #<File:a>
f.binmode?
# => true
f.external_encoding
# => nil
f.binmode
# => #<File:a>
f.binmode?
# => true
f.external_encoding
# => #<Encoding:ASCII-8BIT>
This is because the code to set the encoding is not called if keywords are not provided. If you provide keywords, it works correctly (in the example below you get a warning on Ruby 2.7 for positional hash to keyword conversion):
f = File.open('a', File::WRONLY|File::TRUNC|File::CREAT|File::BINARY, {})
# => #<File:a>
f.binmode?
# => true
f.external_encoding
# => #<Encoding:ASCII-8BIT>
I have submitted a pull request to fix this: https://github.com/ruby/ruby/pull/2985
Updated by jeremyevans (Jeremy Evans) over 4 years ago
- Status changed from Open to Closed
Applied in changeset git|e1e4ea8fa91a0c62dea69977d989d0bb2b526b64.
Set external encoding correctly for File.open('f', FILE::BINARY) on Windows
Previously, the external encoding was only set correctly for
File::BINARY if keyword arguments were provided. This copies
the logic for the keyword arguments case to the no keyword
arguments case. Possibly it should be refactored into a
separate function.
Fixes [Bug #16737]