39

したい:

  • ファイルが存在する場合は、読み書きモードでファイルを開きます。
  • 存在しない場合は作成します。
  • いつでもどこでも切り捨てることができます。

EDIT :切り捨てを使用して、ある位置まで書き込み、ファイルの残りの部分が存在する場合は破棄することを意味します

このすべてをアトミックに(単一のopen()呼び出しまたは単一の呼び出しをシミュレートしてopen()

単一のオープンモダリティが適用されるようには見えません:

  • r : 明らかに機能しません。
  • r+ : ファイルが存在しない場合は失敗します。
  • w: ファイルが存在する場合は再作成します。
  • w+: ファイルが存在する場合は再作成します。
  • a: 読めません。
  • a+: 切り捨てられません。

私が試したいくつかの組み合わせ (rw、rw+、r+w など) も機能しないようです。出来ますか?

Ruby からのいくつかのドキュメント(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

4 に答える 4

32

OpenGroupによると:

O_TRUNC

ファイルが存在し、通常のファイルであり、ファイルが O_RDWR または O_WRONLY で正常に開かれた場合、その長さは 0 に切り捨てられ、モードと所有者は変更されません。FIFO 特殊ファイルまたは端末デバイス ファイルには影響しません。他のファイル タイプへの影響は、実装に依存します。O_RDONLY で O_TRUNC を使用した結果は未定義です。

そのため、「w」または「w+」でファイルを開くと、おそらく O_TRUNC が渡されます。これにより、「切り捨て」に別の意味が与えられますが、私が望むものではありません。

Pythonを使用すると、ソリューションは関数を使用して低レベルのI/Oでファイルを開くようですos.open()

次の 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()
于 2012-04-27T14:10:44.983 に答える
16

まあ、これらのモードだけがあり、それらのすべてにあなたがリストした「欠陥」があります。

あなたの唯一のオプションはラップすることopen()です。なぜこのようなものではないのですか?(パイソン)

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

これは open と同じように動作します。必要に応じて、open() に再バインドすることもできます。

open の機能はすべて保持されます。次のこともできます。

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

もちろん、ファイルを a+ モードで開き、メモリに読み込み、書き込みをインターセプトする contextmanager を作成して、魔法のように w モードで一時ファイルを作成して切り捨てを処理し、閉じるときにその一時ファイルの名前を元のファイルに変更することもできます。しかし、それはやり過ぎだと思います。

于 2012-04-27T12:39:41.190 に答える
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
于 2012-04-27T14:33:27.613 に答える
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なんらかの理由で失敗すると、名前の変更が発生します。

于 2012-04-27T12:39:11.633 に答える