V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Assassinrx
V2EX  ›  Go 编程语言

golang 可能出现文件打开但是报错的情况吗

  •  1
     
  •   Assassinrx · 2023-06-10 10:45:37 +08:00 · 1627 次点击
    这是一个创建于 540 天前的主题,其中的信息可能已经有所发展或是发生改变。
    正常打开文件的模式代码就是这样,我想问下各位大佬可能出现 err 不为空但是文件被打开的情况吗

    file, err := os.Open("filename.txt")
    if err != nil {
    // 处理错误
    }
    defer file.Close()

    因为我想的是可能这么写更好些?

    file, err := os.Open("filename.txt")
    defer file.Close() // defer 写在 err 前面
    if err != nil {
    // 处理错误
    }
    27 条回复    2023-07-25 17:10:29 +08:00
    seers
        1
    seers  
       2023-06-10 11:04:35 +08:00
    defer 是在 return 前才调用
    Assassinrx
        2
    Assassinrx  
    OP
       2023-06-10 11:10:45 +08:00
    @seers 但是一般 error 里面就返回了
    R0n1n
        3
    R0n1n  
       2023-06-10 11:11:12 +08:00
    出错了也就不用再去关闭句柄了,所以一般是先判断 err 吧
    zhs227
        4
    zhs227  
       2023-06-10 11:16:11 +08:00
    第一个 os.Open 如果返回了 err ,那么 file 必定是 nil ,这种情况下不需要 Close 。只有 err == nil 的情况下,才需要在最结尾 close 。
    当然如果按你下面的写法也没错,实际上 file.Close 当 file==nil 的时候,会返回一个 ErrInvalid ,这个你看一下 go 的源码就清楚了。
    twistedmeadows
        5
    twistedmeadows  
       2023-06-10 11:17:20 +08:00 via iPhone
    gpt 答案:
    在 Go 语言中,如果在尝试打开文件时返回的 err 不为 nil ,那么这意味着在打开文件的过程中出现了一些错误。在这种情况下,file 变量通常会是 nil ,所以你无法或者不需要调用 file.Close()。

    全文:
    https://chat.openai.com/share/bb186187-feb5-4970-b36f-6c0914f6e668
    lasuar
        6
    lasuar  
       2023-06-10 11:17:40 +08:00
    看下源码 不就知道了,正常的接口设计不会出现你说的情况
    Assassinrx
        7
    Assassinrx  
    OP
       2023-06-10 11:19:18 +08:00
    @R0n1n 所以我多想了一下,是 golang 都有这个标准,出现 err 就不需要管别的返回了,还是说 err 存在但是 file 也打开了的情况
    Assassinrx
        8
    Assassinrx  
    OP
       2023-06-10 11:21:29 +08:00
    @zhs227 源码是写的 nil ,但是可不可能在系统层面还是打开的,也就是文件里面的引用指针还是+1 了的情况,这块研究不深,所以想问问大佬们
    Assassinrx
        9
    Assassinrx  
    OP
       2023-06-10 11:22:55 +08:00
    @lasuar 我能理解,毕竟这个底层也是 golang 官方库,只是好奇的想确认下文件这块的操作流程是不是符合预期
    Assassinrx
        10
    Assassinrx  
    OP
       2023-06-10 11:24:28 +08:00
    @twistedmeadows 这么想了下也确实
    zhs227
        11
    zhs227  
       2023-06-10 11:25:01 +08:00
    Close 的代码你看一下就懂了,返回为 nil 的时候根本就没涉及到资源处理。
    func (f *File) Close() error {
    if f == nil {
    return ErrInvalid
    }
    return f.file.close()
    }


    Open 的代码:
    func OpenFile(name string, flag int, perm FileMode) (*File, error) {
    testlog.Open(name)
    f, err := openFileNolog(name, flag, perm)
    if err != nil {
    return nil, err
    }
    f.appendMode = flag&O_APPEND != 0

    return f, nil
    }

    要么 f 有值,err==nil ,要么 f==nil ,err 有值。只有这两种可能。而 err 有值的情况下,f==nil 也是不用 close 的。
    aeof
        12
    aeof  
       2023-06-10 11:26:12 +08:00 via Android
    不可能出现
    Assassinrx
        13
    Assassinrx  
    OP
       2023-06-10 11:33:20 +08:00
    @zhs227 好像懂了。也就是 golang 这块 我只要做到正常的处理就行了,底层它内部调用的文件系统是否关闭了文件,我这边也处理不到了。原本是想了解下这个底层是否关闭了,影不影响上层处理。,从写 golang 逻辑下,正常写法就已经是完美了。
    Assassinrx
        14
    Assassinrx  
    OP
       2023-06-10 11:34:22 +08:00
    @aeof 行!
    harrozze
        15
    harrozze  
       2023-06-10 11:57:07 +08:00
    @Assassinrx #8 既然用 go 的库,那么“如果 Open 返回的 err 不为 nil ,而实际系统层面文件是打开的”这件事情应该是 go 需要考虑的,甚至(如果真是这样的话)算是一个 bug 。

    先别想这些细节上的优化,先把代码跑起来,遇到了再说。
    Assassinrx
        16
    Assassinrx  
    OP
       2023-06-10 13:23:55 +08:00
    @harrozze 确实是这样。至少代码层面开发者能做的都做到了。
    admpubcom
        17
    admpubcom  
       2023-06-10 13:41:30 +08:00 via iPhone
    代码就在面前,为什么不点进去看一下呢
    Jirajine
        18
    Jirajine  
       2023-06-10 15:27:49 +08:00
    你只要记住 golang 的 convention 是,调用一个会返回错误的函数时,只在检查完错误之后才能使用其他返回值。没有检查错误或错误不为 nil 时其他返回值都可以认为是无效的,使用此值可以看作 undefined behavior 。
    这主要是因为 go 欠缺 union type 。
    Assassinrx
        19
    Assassinrx  
    OP
       2023-06-10 17:22:32 +08:00
    @admpubcom 我可能想的太多了,纯粹好奇问一下
    Assassinrx
        20
    Assassinrx  
    OP
       2023-06-10 17:24:19 +08:00
    @Jirajine 这个是的,确实能理解了
    flyqie
        21
    flyqie  
       2023-06-11 00:00:27 +08:00 via Android
    @Jirajine #16

    没记错的话,io.EOF 是个例外。。

    不过它不在 Open 而在 Read 用。
    Jirajine
        22
    Jirajine  
       2023-06-11 00:47:27 +08:00
    @flyqie 这个我当然知道,所以说这是 convention ,convention 有例外是很正常的。
    像这种情况在其他类型严格且表达能力足够的语言中,接口可以返回一个专门的 IOResult ,与普通的 Result 区分。
    timpaik
        23
    timpaik  
       2023-06-11 01:12:32 +08:00
    约定俗成,标准库里直接可以认为这俩互斥,但没有类型系统保证,第三方库保险起见看看实现就好了
    realpg
        24
    realpg  
       2023-06-11 02:22:15 +08:00
    golang 提供的官方标准库里,出现了你设想的那种场景,那就是 bug ,golang 官方负责解决,你下层不用想能解决上层的问题。

    你引用了的别人的三方库里出现这种问题,那是哪个库作者的 bug ,库作者负责解决这种问题,你下层不用想能解决上层的问题。
    Assassinrx
        25
    Assassinrx  
    OP
       2023-06-12 13:47:56 +08:00
    @timpaik ok ,了解
    Assassinrx
        26
    Assassinrx  
    OP
       2023-06-12 13:49:00 +08:00
    @realpg 确实是这个道理
    lotusgrm
        27
    lotusgrm  
       2023-07-25 17:10:29 +08:00
    os.Open Go 源码如下:
    func Open(name string) (*File, error) {
    return OpenFile(name, O_RDONLY, 0)
    }

    func OpenFile(name string, flag int, perm FileMode) (*File, error) {
    testlog.Open(name)
    f, err := openFileNolog(name, flag, perm)
    if err != nil {
    return nil, err
    }
    f.appendMode = flag&O_APPEND != 0

    return f, nil
    }

    从这里可以看到,如果 open file 的时候,出现了 error ,os.Open 返回的第一个值是 nil, 那么此时也就不需要再进行 close
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2443 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 04:48 · PVG 12:48 · LAX 20:48 · JFK 23:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.