File Opening Mode in Ruby

What are the Ruby File.open modes and options?

In Ruby IO module documentation, I suppose.

Mode |  Meaning
-----+--------------------------------------------------------
"r" | Read-only, starts at beginning of file (default mode).
-----+--------------------------------------------------------
"r+" | Read-write, starts at beginning of file.
-----+--------------------------------------------------------
"w" | Write-only, truncates existing file
| to zero length or creates a new file for writing.
-----+--------------------------------------------------------
"w+" | Read-write, truncates existing file to zero length
| or creates a new file for reading and writing.
-----+--------------------------------------------------------
"a" | Write-only, starts at end of file if file exists,
| otherwise creates a new file for writing.
-----+--------------------------------------------------------
"a+" | Read-write, starts at end of file if file exists,
| otherwise creates a new file for reading and
| writing.
-----+--------------------------------------------------------
"b" | Binary file mode (may appear with
| any of the key letters listed above).
| Suppresses EOL <-> CRLF conversion on Windows. And
| sets external encoding to ASCII-8BIT unless explicitly
| specified.
-----+--------------------------------------------------------
"t" | Text file mode (may appear with
| any of the key letters listed above except "b").

File opening mode in Ruby

The file open modes are not really specific to ruby - they are part of IEEE Std 1003.1 (Single UNIX Specification). You can read more about it here:

http://pubs.opengroup.org/onlinepubs/009695399/functions/fopen.html

r or rb
Open file for reading.

w or wb
Truncate to zero length or create file for writing.

a or ab
Append; open or create file for writing at end-of-file.

r+ or rb+ or r+b
Open file for update (reading and writing).

w+ or wb+ or w+b
Truncate to zero length or create file for update.

a+ or ab+ or a+b
Append; open or create file for update, writing at end-of-file.

Any mode that contains the letter 'b' stands for binary file. If the 'b' is not present is a 'plain text' file.

The difference between 'open' and 'open for update' is indicated as:

When a file is opened with update mode ( '+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, the application shall ensure that output is not directly followed by input without an intervening call to fflush() or to a file positioning function ( fseek(), fsetpos(), or rewind()), and input is not directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.

Difference between the access modes of the `File` object (ie. w+, r+)

See http://www.tutorialspoint.com/ruby/ruby_input_output.htm

To quote:

r

Read-only mode. The file pointer is placed at the beginning of the file. This is the default mode.

r+

Read-write mode. The file pointer will be at the beginning of the file.

w

Write-only mode. Overwrites the file if the file exists. If the file does not exist, creates a new file for writing.

w+

Read-write mode. Overwrites the existing file if the file exists. If the file does not exist, creates a new file for reading and writing.

a

Write-only mode. The file pointer is at the end of the file if the file exists. That is, the file is in the append mode. If the file does not exist, it creates a new file for writing.

a+

Read and write mode. The file pointer is at the end of the file if the file exists. The file opens in the append mode. If the file does not exist, it creates a new file for reading and writing.

(empshasis mine.)

r+, w+, and a+ all do read-write. w+ truncates the file. a+ appends. w+ and a+ both create the file if it does not exist.)

How to get file mode in ruby?

You can use file.readable?, which returns true or false.

Please check this link.

How to test what type of mode a Ruby File was opened in?

You could try any of:

  • Write a single character to the file descriptor, and then unseek back; if you succeed you are in write mode, otherwise you raise an exception.

  • Try and glean information of the fstat method.

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')

Ruby's File.open and the need for f.close

I saw many times in ruby codes unmatched File.open calls

Can you give an example? I only ever see that in code written by newbies who lack the "common knowledge in most programming languages that the flow for working with files is open-use-close".

Experienced Rubyists either explicitly close their files, or, more idiomatically, use the block form of File.open, which automatically closes the file for you. Its implementation basically looks something like like this:

def File.open(*args, &block)
return open_with_block(*args, &block) if block_given?
open_without_block(*args)
end

def File.open_without_block(*args)
# do whatever ...
end

def File.open_with_block(*args)
yield f = open_without_block(*args)
ensure
f.close
end

Scripts are a special case. Scripts generally run so short, and use so few file descriptors that it simply doesn't make sense to close them, since the operating system will close them anyway when the script exits.

Do we need to explicitly close?

Yes.

If yes then why does the GC autoclose?

Because after it has collected the object, there is no way for you to close the file anymore, and thus you would leak file descriptors.

Note that it's not the garbage collector that closes the files. The garbage collector simply executes any finalizers for an object before it collects it. It just so happens that the File class defines a finalizer which closes the file.

If not then why the option?

Because wasted memory is cheap, but wasted file descriptors aren't. Therefore, it doesn't make sense to tie the lifetime of a file descriptor to the lifetime of some chunk of memory.

You simply cannot predict when the garbage collector will run. You cannot even predict if it will run at all: if you never run out of memory, the garbage collector will never run, therefore the finalizer will never run, therefore the file will never be closed.



Related Topics



Leave a reply



Submit