陈阿达
陈阿达

Reputation: 9

Close the file before rename it in golang

When I do some file operations with golang, I firstly open a file and add the close() into defer list, then I try to rename that file. If I close the file manually, the defer will close it again. If I wait for the defer to close it, the rename will cause error because it is not closed yey. Code as below

func main() {

    pfile1, _ := os.Open("myfile.log")
    defer pfile1.Close() //It will be closed again.
    ...
    ...
    pfile1.Close() //I have to close it before rename it.
    os.Rename("myfile.log", "myfile1.log")
}

I found some ugly solution, such as create another function to separate the open file, does any better solution that below?

func main() {

    var pfile1 *os.File
    ugly_solution(pfile1)

    os.Rename("myfile.log", "myfile1.log")
}

func ugly_solution(file *os.File) {
    file, _ = os.Open("myfile.log")
defer file.Close()
}

Upvotes: 0

Views: 5463

Answers (3)

Stilmant Michael
Stilmant Michael

Reputation: 31

In situation like in your sample

Maybe you want to follow this scenario:

  • Create easily an identifiable temporary file.
  • Write the data.
  • Close the file.
  • If successful rename the file.

In that case where you want to follow OS system action of underlying files maybe you want to simply not deferring the close on IO.file since you want to get the Error returned by the close function itself.

Also, in that case you maybe want to operate a file.sync() too.

See https://www.joeshaw.org/dont-defer-close-on-writable-files/

Upvotes: 0

fl0cke
fl0cke

Reputation: 2884

You can put both closing and renaming the file in the defer:

func main() { 
    pfile1, _ := os.Open("myfile.log")
    defer func(){
        pfile1.Close()
        os.Rename("myfile.log", "myfile1.log")   
    }() 
    ...
    ...
}

Upvotes: 2

Simone Carletti
Simone Carletti

Reputation: 176382

There are a few things that are not clear to me about your code.

First of all, why do you open the file before renaming it? This is not required by the os.Rename function. The function takes two strings representing the old and new file name, there is no need to pass a file pointer.

func main() {
    ...
    ...
    os.Rename("myfile.log", "myfile1.log")
}

Assuming you need to make changes to the file content (which doesn't seem to be the case given the ugly_solution method) and you have to open the file, then why deferring file.Close()? You don't have to defer the method if you need it to be called explicitly somewhere in the same method. Simply call it.

func main() {
    pfile1, _ := os.Open("myfile.log")
    ...
    ...
    pfile1.Close()
    os.Rename("myfile.log", "myfile1.log")
}

Upvotes: 2

Related Questions