在GLib中等效的开放(O_WRONLY | O_CREAT)?

时间:2018-05-21 15:30:25

标签: c glib vala gio

我需要打开一个文件进行写作。如果文件已经存在,我不想截断它。

换句话说,在简单的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返回GFileOutputStreamGFileIOStream,但我看不到有人做我想做的事。

我错过了什么吗?

我是否需要将这个简单的任务分成几个小任务? (检查文件是否存在;如果存在,则创建,否则打开;所有以某种方式包裹在锁中。)

(BTW,如果重要的话:我的文件将驻留在本地文件系统上,而不是网络文件系统。此外,我在Vala工作,这就是为什么我不只是使用open()(也许我可以找到它的绑定,但我更喜欢学习GIO的做事方式。)

3 个答案:

答案 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_WRONLYO_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