等效于 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 会返回GFileOutputStream
或GFileiostream
,但我看不到有一个可以满足我的要求。
我错过了什么吗?
我需要把这个简单的任务分成几个小任务吗? (检查文件是否存在;如果存在,则创建,否则打开;都以某种方式包裹在锁中。)
(顺便说一句,如果重要的话:我的文件将驻留在本地文件系统上,而不是网络文件系统上。另外,我在 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_WRONLY
和 O_CREAT
。
【讨论】:
谢谢,但我不能使用append_to()
,因为我不会写在文件的末尾,而是写在里面的某个随机位置。 (感谢 Posix 指针:很高兴看到这个绑定是有效内置的。)
append_to ()
返回一个具有seek
方法的FileOutputStream
。 append_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)?的主要内容,如果未能解决你的问题,请参考以下文章
等效于 Riverpod 中的 ChangeNotifierProvider 小部件