等效于 GLib 中的 open(O_WRONLY | O_CREAT)?

Posted

技术标签:

【中文标题】等效于 GLib 中的 open(O_WRONLY | O_CREAT)?【英文标题】:Equivalent of open(O_WRONLY | O_CREAT) in GLib? 【发布时间】:2018-10-31 07:13:26 【问题描述】:

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

换句话说,在纯 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,但我看不到有一个可以满足我的要求。

我错过了什么吗?

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

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

【问题讨论】:

好像没有这个功能。也许您可以检查g_file_create 的返回码是否为G_IO_ERROR_EXISTS,而不是将其视为失败? 【参考方案1】:

我最终分两步完成了这项工作。我使用了@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;
    
  


(这里可能存在竞争条件,但与我的情况无关。)

【讨论】:

【参考方案2】:

Valadoc.org 文档有很好的示例,所以我不会在这里编写一个工作示例。我认为你需要GLib.File.new_for_path ()GLib.File.append_to ()g_file_append_to () 的 C 文档建议“获取用于将数据附加到文件的输出流。如果文件不存在,则创建它。请注意,append_to () 采用 FileCreateFlags 参数。还有一个异步版本的 append_to () 用于 Vala,append_to_async ()

顺便说一下,open () 的 Vala 绑定在 Posix VAPI 中。请参阅 Valadoc.org 上的 open ()O_WRONLYO_CREAT

【讨论】:

谢谢,但我不能使用append_to(),因为我不会写在文件的末尾,而是写在里面的某个随机位置。 (感谢 Posix 指针:很高兴看到这个绑定是有效内置的。) append_to () 返回一个具有seek 方法的FileOutputStreamappend_to () 将当前位置设置为文件末尾,但您可以根据需要更改位置。 不是这样。 append_to() 具有 O_APPEND 的语义,open(2) 的手册页将其描述为:“在 each write(2) 之前,文件偏移位于文件末尾 [... ] 作为单个原子步骤执行”。我已经just verified 认为这也适用于 Vala 的 GIO。【参考方案3】:

上游官方的回答是,GIO 作为一个高级抽象层,最初并不是为了保证原子的创建或打开操作(如O_CREAT),所以你有两种选择:

尝试创建文件,如果失败并显示G_IO_ERROR_EXISTS,请尝试打开它;如your answer。 使用open()O_CREAT 创建/打开文件(如问题中所示),并将FD 传递给g_unix_output_stream_new() 以创建一个新的GOutputStream 包装FD 并且您可以像写入一样写入由g_file_create()返回。

请注意,g_unix_output_stream_new() 不能移植到非 Unix 平台,但这似乎与您的情况无关。如果您确实关心消除竞争条件,则推荐使用第二个选项。

请注意,还有其他原因可以避免竞争条件:更少的代码、更少的系统调用(这意味着更好的性能)和更易读的代码(如果你忽略了 open() API 的突然命名)。

将来可能会支持直接使用 GFile 上的方法执行此操作:GLib 中有一个 open issue about supporting it。

【讨论】:

以上是关于等效于 GLib 中的 open(O_WRONLY | O_CREAT)?的主要内容,如果未能解决你的问题,请参考以下文章

软件安全实验——pre2

等效于 Riverpod 中的 ChangeNotifierProvider 小部件

python中的GNU拆分等效于啥? [复制]

等效于 Julia 中的 c\c++ 编译器指令

等效于 Javascript 中的 python 范围 [重复]

SQLAlchemy 等效于 ActiveRecord 中的命名范围