我需要打开一个文件进行写作。如果文件已经存在,我不想截断它。
换句话说,在简单的C中我会这样做:
int fd = open("output.bin", O_WRONLY | O_CREAT, 0666);
// I don't mind using O_RDWR, btw.
我正在尝试与GLib的GFile(GIO的一部分)做类似的事情。我第一次尝试:
g_file_create(gfile, G_FILE_CREATE_NONE, NULL, NULL);
但如果文件已经存在,则会失败。
我看到有about 5 other functions返回GFileOutputStream
或GFileIOStream
,但我看不到有人做我想做的事。
我错过了什么吗?
我是否需要将这个简单的任务分成几个小任务? (检查文件是否存在;如果存在,则创建,否则打开;所有以某种方式包裹在锁中。)
(BTW,如果重要的话:我的文件将驻留在本地文件系统上,而不是网络文件系统。此外,我在Vala工作,这就是为什么我不只是使用open()
(也许我可以找到它的绑定,但我更喜欢学习GIO的做事方式。)
答案 0 :(得分:3)
我最后分两步完成了这项工作。我使用@ usr建议检查G_IO_ERROR_EXISTS
。我的代码:
public class Downloader {
public FileIOStream iostream;
public OutputStream output { get { return iostream.output_stream; } }
public void create_output_file() throws Error
{
File file = File.new_for_path("output.bin");
try {
// If file doesn't exist.
iostream = file.create_readwrite(NONE);
} catch (Error e) {
if (e is IOError.EXISTS)
// It exists.
iostream = file.open_readwrite();
else
throw e;
}
}
}
(这里可能存在竞争条件,但在我的情况下这无关紧要。)
答案 1 :(得分:2)
Valadoc.org文档有很好的例子,所以我不会在这里编写一个工作示例。我认为您需要GLib.File.new_for_path ()
和GLib.File.append_to ()
。 g_file_append_to ()
的C文档建议'获取用于将数据附加到文件的输出流。如果该文件尚不存在,则会创建该文件。请注意,append_to ()
采用FileCreateFlags
参数。 Vala还有一个append_to ()
的异步版本,append_to_async ()
。
顺便说一下,open ()
的Vala绑定在Posix VAPI中。在Valadoc.org上查看open ()
,O_WRONLY
和O_CREAT
。
答案 2 :(得分:0)
官方上游的答案是,GIO作为一个高级抽象层,最初并不是为了保证原子创建或打开操作(与O_CREAT
一样),所以你有两个选择:
G_IO_ERROR_EXISTS
,请尝试打开它;如your answer。open()
O_CREAT
创建/打开文件(如问题所示),并将FD传递给g_unix_output_stream_new()
以创建包装FD的新GOutputStream
你可以像g_file_create()
一样回复。请注意,g_unix_output_stream_new()
无法移植到非Unix平台,但在您的情况下似乎并不相关。如果你关心消除竞争条件,那么推荐使用第二个选项。
请注意,还有其他原因可以避免竞争条件:更少的代码,更少的系统调用(这意味着更好的性能)和更易读的代码(如果忽略open()
API的突然命名)。
将来可能会支持使用GFile
上的方法直接执行此操作:GLib中有open issue about supporting it。