我需要将一些日志存储在一个文件中,该文件可以随着每次执行而增长。一种合乎逻辑的方法是在打开时使用a+
选项,因为使用w+
会截断文件。但是,使用a+
选项(Tcl 8.4),我无法在文件中的任何位置写入。 seek
工作正常。我可以使用tell
验证指针是否已移动。但输出始终在文件的尾端处完成。
有什么方法可以解决这个问题吗?即能够在任何地方寻找和写作,并在开放时保留旧文件。
答案 0 :(得分:4)
在Tcl 8.5中,改变了Unix 上Tcl 的行为,以便将O_APPEND
标志传递给open()
系统调用。这导致OS始终将数据附加到文件,并在FD传递给子进程时继承;对于日志,完全是正确的。 (在8.4及之前,在Windows上的所有版本中,行为都是在Tcl的文件通道实现中模拟的,它将在seek()
之前的内部write()
进行模拟;这显然会受到潜在问题的影响当有多个进程记录到同一个文件时具有竞争条件,并且当FD传递给子进程时肯定是不安全的。)您可以使用chan truncate
(8.5中的新增功能)管理已打开文件的截断,这样可以正常工作在a+
- 已打开的文件。
如果您不想要搜索到结束行为,则不应使用a+
(或a
)。试试r+
或flags的某种组合,如下所示:
set f [open $filename {RDWR CREAT}]
为了进行比较,a+
选项现在与<{1}}完全相同,并且并非所有较长标志的组合都可以通过短格式标志说明符来描述。如果您未指定RDWR CREAT APPEND
,则需要自己执行APPEND
(如果您要附加日志,请注意多个进程的问题;那时seek $f 0 end
成为APPEND
需要并且特别难以正确模拟任何其他方式。)
答案 1 :(得分:3)
以r+
打开 - 它以读取模式打开(因此不会对文件进行转换),但也允许写入。
有关详细信息,请参阅open
的文档:http://www.tcl.tk/man/tcl8.5/TclCmd/open.htm
答案 2 :(得分:0)
我已经确认使用a+
选项允许我在文件中的任何位置读/写。但是,通过在文件的中间(或开头)写入,我覆盖那里的数据,而不是插入。以下代码说明了这一点:
#!/usr/bin/env tclsh
# Open the file, with truncation
set f [open foo w]
puts $f "one"
puts $f "two"
close $f
# Open again, with a+ ==> read/write/append
set f [open foo a+]
puts $f "three" ;# This goes to the end of the file
seek $f 4 ;# Seek to the beginning of the word "two"
puts $f "2.0" ;# Overwrite the word "two"
close $f
# Open and verify the contents
set f [open foo r]
puts [read $f]
close $f
输出:
one
2.0
three
如果要在文件中间插入,可能需要查看包含fileutil
命令的::fileutil::insertIntoFile
包。