Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to open (read-write) or create a file with truncation allowed?

I want to:

  • open a file in read-write mode if it exists;
  • create it if it doesn't exist;
  • be able to truncate it anytime-anywhere.

EDIT: with truncate I mean write until a position and discard the remaining part of the file, if present

All this atomically (with a single open() call or simulating a single open() call)

No single open modality seems to apply:

  • r : obviously doesn't work;
  • r+ : fails if the file doesn't exist;
  • w: recreate the file if it exists;
  • w+: recreate the file if it exists;
  • a: can't read;
  • a+: can't truncate.

Some combinations I tried (rw, rw+, r+w, etc.) seems to not work either. Is it possible?

Some doc from Ruby (applies to python too):

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. 
like image 351
ceztko Avatar asked Apr 27 '12 11:04

ceztko


People also ask

How do I open read and write files?

'r+' opens the file for both reading and writing. On Windows, 'b' appended to the mode opens the file in binary mode, so there are also modes like 'rb', 'wb', and 'r+b'. Also reading then writing works equally well using 'r+b' mode, but you have to use f.

What is file truncation?

In databases and computer networking data truncation occurs when data or a data stream (such as a file) is stored in a location too short to hold its entire length.

What does truncate () do in Python?

Python File truncate() Method The truncate() method resizes the file to the given number of bytes. If the size is not specified, the current position will be used.


1 Answers

According to OpenGroup:

O_TRUNC

If the file exists and is a regular file, and the file is successfully opened O_RDWR or O_WRONLY, its length is truncated to 0 and the mode and owner are unchanged. It will have no effect on FIFO special files or terminal device files. Its effect on other file types is implementation-dependent. The result of using O_TRUNC with O_RDONLY is undefined.

So, O_TRUNC is probably passed when opening a file with "w" or "w+". This gives "truncation" a different meaning, not what I want.

With python the solution seems to open file at low-level I/O with os.open() function.

The following python function:

def touchopen(filename, *args, **kwargs):     # Open the file in R/W and create if it doesn't exist. *Don't* pass O_TRUNC     fd = os.open(filename, os.O_RDWR | os.O_CREAT)      # Encapsulate the low-level file descriptor in a python file object     return os.fdopen(fd, *args, **kwargs) 

has the behavior I wanted. You can use it like this (it's in fact my use case):

# Open an existing file or create if it doesn't exist with touchopen("./tool.run", "r+") as doing_fd:      # Acquire a non-blocking exclusive lock     fcntl.lockf(doing_fd, fcntl.LOCK_EX)      # Read a previous value if present     previous_value = doing_fd.read()     print previous_value       # Write the new value and truncate     doing_fd.seek(0)     doing_fd.write("new value")     doing_fd.truncate() 
like image 189
ceztko Avatar answered Oct 04 '22 15:10

ceztko