如何打开(读写)或创建允许截断的文件?

时间:2012-04-27 11:27:13

标签: python ruby truncate

我想:

  • 以读写模式打开文件(如果存在);
  • 如果它不存在则创建它;
  • 能够随时随地截断它。

编辑:有截断我的意思是写一个位置并丢弃文件的剩余部分(如果存在)

所有这些原子(通过单个open()调用或模拟单个open()调用)

似乎没有单一的开放模态适用:

  • r:显然不起作用;
  • r +:如果文件不存在则失败;
  • w:重新创建文件(如果存在);
  • w +:重新创建文件(如果存在);
  • a:看不懂;
  • a +:不能截断。

我试过的一些组合(rw,rw +,r + w等)似乎也不起作用。有可能吗?

Ruby中的一些doc(也适用于python):

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.

4 个答案:

答案 0 :(得分:30)

根据OpenGroup

  

O_TRUNC

     

如果文件存在且是常规文件,则文件成功       打开O_RDWR或O_WRONLY,其长度被截断为0和模式       和所有者不变。它对FIFO特殊文件没有影响       或终端设备文件。它对其他文件类型的影响是       实现有关。将O_TRUNC与O_RDONLY一起使用的结果是       未定义。

因此,当打开带有“w”或“w +”的文件时,可能会传递O_TRUNC。这使得“截断”具有不同的意义,而不是我想要的意思。

使用python,解决方案似乎在具有os.open()功能的低级I / O中打开文件。

以下python函数:

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)

有我想要的行为。您可以像这样使用它(实际上是我的用例):

# 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()

答案 1 :(得分:14)

嗯,只有这些模式,并且所有模式都列出了您所列的“缺陷”。

您唯一的选择是包裹open()。 为什么不这样的? (Python)的

def touchopen(filename, *args, **kwargs):
    open(filename, "a").close() # "touch" file
    return open(filename, *args, **kwargs)

它的行为就像打开一样,如果你真的愿意,你甚至可以将它重新绑定到open()。

保留所有open的功能,你甚至可以这样做:

with touchopen("testfile", "r+") as testfile:
    do_stuff()

您当然可以创建一个上下文管理器,以+模式打开文件,将其读入内存,并拦截写入,以便通过在w模式下神奇地创建临时文件来处理截断,并在您使用时将该tempfile重命名为原始文件关闭它,但我想这会有点过分。

答案 2 :(得分:2)

您可以使用“a +”(Ruby)读取,写入和截断:

File.open("test.txt", "a+") do |f|
  f.print "abc\ndefgh" 
  f.rewind
  p f.read 
  f.truncate(5) 
end
puts File.size("test.txt") #=> 5

答案 3 :(得分:0)

我不知道在Ruby中做这件事的任何优雅方式。我的解决方案可能是创建一个临时文件,向其写入内容,然后将其重命名为我真正想要的文件名。这将覆盖先前的文件(如果存在),或者如果不存在则创建文件。像这样:

orig_filename = './whatever_file.log'
temp_filename = './.tempfile'
temp_file = File.new(temp_filename, 'w')

// Write contents to file

temp_file.close
File.rename(temp_filename, orig_filename)

如果因任何原因失败,重命名将引发SystemCallError