Issue #16737 has been updated by jeremyevans0 (Jeremy Evans).


I agree with @nobu that this isn't a bug on !Windows.  The documentation fo=
r `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:

```ruby
f =3D File.open('a', File::WRONLY|File::TRUNC|File::CREAT|File::BINARY)
# =3D> #<File:a>
f.binmode?
# =3D> true
f.external_encoding
# =3D> nil
f.binmode
# =3D> #<File:a>
f.binmode?
# =3D> true
f.external_encoding
# =3D> #<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 conversi=
on):

```ruby
f =3D File.open('a', File::WRONLY|File::TRUNC|File::CREAT|File::BINARY, {})
# =3D> #<File:a>
f.binmode?
# =3D> true
f.external_encoding
# =3D> #<Encoding:ASCII-8BIT>
```

I have submitted a pull request to fix this: https://github.com/ruby/ruby/p=
ull/2985

----------------------------------------
Bug #16737: File::BINARY doesn't work
https://bugs.ruby-lang.org/issues/16737#change-84793

* Author: sos4nt (Stefan Sch=FC=DFler)
* Status: Open
* Priority: Normal
* Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN
----------------------------------------
`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:

```ruby
# this works:
File.open('foo', 'wb') do |f|
  p f.binmode?
  p f.external_encoding
end
#=3D> true
#=3D> #<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
#=3D> false
#=3D> nil
```

Further inspecting `File::BINARY` reveals that it has a value of zero:

```ruby
File::BINARY #=3D> 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 abo=
ve behavior. (I'm on macOS if that matters)

I'm aware that I can achieve the desired result by using a string mode or b=
y passing `binary: true`. But since Ruby accepts `mode` to be given as an i=
nteger, there should be a (working) "b" equivalent.



-- =

https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=3Dunsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>