Project

General

Profile

Actions

Bug #16737

closed

File::BINARY doesn't work

Added by sos4nt (Stefan Schüßler) over 4 years ago. Updated over 4 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:97582]

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

Actions #4

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]

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0