"defer f.Close()" - error return ignored?

4,123 views
Skip to first unread message

Igor Nazarenko

unread,
Nov 16, 2011, 2:49:53 PM11/16/11
to golang-nuts
In many places in the documentation I see the "defer f.Close()" idiom
used to close files. However, looking at the godoc for os.Close, it
actually returns an error. What happens to the error return when the
Close() call is deferred?

Dave Cheney

unread,
Nov 16, 2011, 4:12:49 PM11/16/11
to Igor Nazarenko, golang-nuts
It is discarded.

Sent from my iPad

Jan Mercl

unread,
Nov 16, 2011, 4:33:38 PM11/16/11
to golan...@googlegroups.com, Igor Nazarenko
On Wednesday, November 16, 2011 10:12:49 PM UTC+1, Dave Cheney wrote:
It is discarded.

Correct. Anyway, it's possible to use the retval if needed:

defer func() {
        if err := f.Close(); err != nil {
                // handle/do something with err
        }
}()

It may be a good idea to not ignore errors returned by os.File.Close(). OTOH, I think such errors mostly can't be easily remedied beyond reporting them somehow to the caller.

Ian Lance Taylor

unread,
Nov 16, 2011, 5:41:09 PM11/16/11
to Dave Cheney, Igor Nazarenko, golang-nuts
Dave Cheney <da...@cheney.net> writes:

> It is discarded.

So it is probably not a good idea to use this idiom for a file open for
writing. But it is fine in practice to do this with a file open only
for reading. There is nothing interesting to be done for an error when
closing a file open for reading.

Ian

Константин Изюмов

unread,
Feb 16, 2017, 1:57:37 PM2/16/17
to golang-nuts, da...@cheney.net, inaza...@google.com
In my point of view - let`s try that:

-------------------------------------------
// Copy - copy files
func Copy(inputFileName, outputFileName string) (err error) {

if len(inputFileName) == 0 {
return fmt.Errorf("inputFileName is zero: %s", inputFileName)
}

if len(outputFileName) == 0 {
return fmt.Errorf("inputFileName is zero: %s", outputFileName)
}

inputFile, err := os.Open(inputFileName)
if err != nil {
return err
}
defer func() {
errFile := inputFile.Close()
if errFile != nil {
if err != nil {
err = fmt.Errorf("%v ; %v", err, errFile)
} else {
err = errFile
}
}
}()

outputFile, err := os.Create(outputFileName)
if err != nil {
return err
}
defer func() {
errFile := outputFile.Close()
if errFile != nil {
if err != nil {
err = fmt.Errorf("%v ; %v", err, errFile)
} else {
err = errFile
}
}
}()

_, err = io.Copy(outputFile, inputFile)
if err != nil {
return err
}

return nil
}
-------------------------------------------

Jakob Borg

unread,
Feb 16, 2017, 2:46:17 PM2/16/17
to 'Eric Johnson' via golang-nuts
Deferred close on the input file is fine, no need for closure shenanigans. On the output file, you'll get cleaner code here by not using defer at all.

    outputFile, err := os.Create(outputFileName)
    if err != nil {
        return err
    }
    _, err = io.Copy(outputFile, inputFile)
    if err != nil {
        outputFile.Close() // don't care about the error
        return err
    }
    return outputFile.Close()
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages