1

If I run this code:

package main
import "os"
func pass() bool { return false }

func main() {
   f, e := os.Create("file.txt")
   if e != nil {
      panic(e)
   }
   defer f.Close()
   if ! pass() {
      e := os.Remove("file.txt")
      if e != nil {
         panic(e)
      }
   }
}

I get this result:

The process cannot access the file because it is being used by another process.

If I do this instead, I get expected result:

defer f.Close()
if ! pass() {
   f.Close()
   e := os.Remove("file.txt")
   if e != nil {
      panic(e)
   }
}

but I would like to avoid the duplicate Close() if possible. The file always needs to be closed, but also removed if some function fails. Is a better way available for what I am trying to do? To respond to comment: the file will be written to from multiple HTTP requests. It's possible first request could pass, and second request fail.

Nimantha
  • 6,405
  • 6
  • 28
  • 69
Zombo
  • 1
  • 62
  • 391
  • 407
  • 3
    Then don't `defer`. Explicitly close the file when you're done writing to it. `defer`s are only useful when contained within a function/closure context. – colm.anseo May 11 '21 at 21:28
  • 2
    Why not create the file `if pass()`? Do you need the file to be created regardless of whether is function pass or fail? Otherwise, this is over-engineering it. – Prav May 11 '21 at 21:36
  • Does the file name change depending on the request? Or is it a fixed file at all times? Are you attempting to deal with multipart file upload by chance? – Prav May 11 '21 at 21:48

1 Answers1

3

If this situation comes up frequently, then create a helper function:

func nuke(f *os.File) {
   name := f.Name()
   f.Close()
   if err := os.Remove(name); err != nil {
      panic(err)
   }
}

Use it like this:

func main() {
   f, e := os.Create("file.txt")
   if e != nil {
      panic(e)
   }
   defer f.Close()
   if ! pass() {
      nuke(f)
   }
}