【问题标题】:Safely close a file descriptor in golang在 golang 中安全关闭文件描述符
【发布时间】:2021-02-20 23:14:58
【问题描述】:

另一个问题How to read/write from/to file using Go? 在评论中涉及安全关闭文件描述符。

请注意,这些示例并未检查从 fo.Close()。来自 Linux 手册页 close(2):不检查返回 close() 的值是一种常见但仍然很严肃的编程 错误。以前的写入很可能出错(2) 操作首先在最后的 close() 中报告。不检查 关闭文件时的返回值可能会导致数据无声丢失。 这在 NFS 和磁盘配额中尤其明显。 – 尼克 Craig-Wood 2013 年 1 月 25 日在 7:12

更新帖子的解决方案使用了恐慌:

// close fo on exit and check for its returned error
defer func() {
    if err := fo.Close(); err != nil {
        panic(err)
    }
}()

我想将此错误作为一个值而不是恐慌。

【问题讨论】:

    标签: go


    【解决方案1】:

    如果我们害怕写不完close是不够的,所以更新错误还是不正确。

    如果你不想点击它,正确的解决方案是fsync文件:

    defer(fd.Close())
    // Do stuff
    return fd.Sync()
    

    通过延迟或在整个函数中维护返回一个非零修改错误更容易阅读。

    这会影响性能,但会捕获写入缓冲区的关闭错误和物理写入磁盘的错误。

    【讨论】:

    • «这意味着必须在每个函数中定义匿名函数»是错误的声明。比如说,您可以声明 func checkedClose(c io.Closer, perr *error) 并使用 defer checkedClose(fd, &err) 安排其延迟调用。 IOW,这是指向接口值的指针派上用场的罕见情况之一。
    • 要考虑的另一件事是,您似乎已经专注于处理延迟调用中的错误的机制,这些机制会释放文件等外部资源,而机制本身则是次要的。请注意,在您的解决方案中,您已经在关闭文件时将错误的静音替换为将消息写入标准错误流(或任何log 的输出被重定向,如果完成)。虽然这可能比完全忽略错误稍微好一点,但您仍然很难调整通用解决方案来执行......
    • …对关闭调用失败的有用操作。有很多事情需要考虑:文件是否以只读方式打开?如果是,并且读取发生时没有错误,则可能会忽略关闭文件的失败(可能会记录警告,但否则您是安全的)。是否打开文件进行写入?如果是,那么未能关闭它可能确实很严重。如果是这样,仅仅一个警告可能是不够的:您可能想要标记整个操作(其中写入此文件是其中的一部分)失败,或者您可能希望以交互方式允许用户重试保存或完全其他的东西。
    • @kostix 关于接口参考的要点!我一定会做出这样的改变。至于示例代码,它只是显示功能。在我的实际用例中,使用 truncate 和 write 打开文件,然后我使用 os.Copy 读取临时文件内容并写入 fd。我没有重试功能 rn,但如果 fn 返回关闭错误,这可能是正确的解决方案。
    • 在谈论 Go 时,请考虑在大多数情况下不要使用“引用”这个词;-) Go 没有引用;它有多个内置类型,当它们的值被传递时可以说是具有引用语义(这些类型是切片、字符串、映射、通道、函数和指针),以及任何用户定义的struct 类型包括一个具有引用语义的字段,它自动“继承”这些。但是,Go 仍然没有引用(例如,C++ 和 C# 将它们作为语言概念,但 Go 没有),它有指针,我建议使用指针 ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 2014-03-28
    • 1970-01-01
    • 2014-04-06
    • 2011-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多