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
How to Find the Unique Elements in an Array in Ruby
Rails and Os X: How to Install Rmagick
How to Get Sinatra to Refrain from Adding the X-Frame-Options Header
Understanding How Establish_Connection Works in Activerecord
Os X Mountain Lion: Gcc-4.2 No Such File or Directory
Simple Encryption in Ruby Without External Gems
Rails on Windows Is So Slow (Rails -V Takes 4 Seconds)
Forming Sanitary Shell Commands or System Calls in Ruby
Digital Signature Verification with Openssl
Rails Forms for Has_Many Through Association with Additional Attributes
Dividing Elements of a Ruby Array into an Exact Number of (Nearly) Equal-Sized Sub-Arrays
Add Method to an Instanced Object
Getting an Ascii Character Code in Ruby Using '' (Question Mark) Fails
How to Unzip a File in Ruby on Rails
Using Implicit 'Subject' with 'Expect' in Rspec-2.11
How to Uninstall Ruby from /Usr/Local