Закройте файл, прежде чем переименовывать его в golang

Когда я выполняю какие-то файловые операции с golang, я сначала открываю файл и добавляю close() в список отложенных, а затем пытаюсь переименовать этот файл. Если я закрою файл вручную, отсрочка снова его закроет. Если я подожду, пока отсрочка закроет его, переименование вызовет ошибку, потому что он еще не закрыт. Код, как показано ниже

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")
}

Я нашел какое-то уродливое решение, например, создать еще одну функцию для разделения открытого файла, есть ли лучшее решение, чем ниже?

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()
}

person 陈阿达    schedule 06.03.2016    source источник
comment
почему вы все равно откладываете вызов Close()? Если вам нужно позвонить, вы можете просто оставить отсрочку?   -  person nemo    schedule 06.03.2016


Ответы (3)


Вы можете поставить как закрытие, так и переименование файла в отложенном:

func main() { 
    pfile1, _ := os.Open("myfile.log")
    defer func(){
        pfile1.Close()
        os.Rename("myfile.log", "myfile1.log")   
    }() 
    ...
    ...
}
person fl0cke    schedule 06.03.2016
comment
Но переименование будет вызвано при выходе из функции, возможно, я хочу добавить больше кода после переименования. Он не будет гибким. - person 陈阿达; 06.03.2016

Есть несколько вещей, которые мне непонятны в вашем коде.

Прежде всего, почему вы открываете файл, прежде чем переименовать его? Это не требуется для функции os.Rename. Функция принимает две строки, представляющие старое и новое имя файла, нет необходимости передавать указатель файла.

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

Предполагая, что вам нужно внести изменения в содержимое файла (что, похоже, не так, учитывая метод ugly_solution) и вам нужно открыть файл, тогда зачем откладывать file.Close()? Вам не нужно откладывать метод, если вам нужно, чтобы он вызывался явно где-то в том же методе. Просто позвоните.

func main() {
    pfile1, _ := os.Open("myfile.log")
    ...
    ...
    pfile1.Close()
    os.Rename("myfile.log", "myfile1.log")
}
person Simone Carletti    schedule 06.03.2016
comment
Да, я хочу внести изменения в файл, а затем переименовать его. Как предложение, он не будет добавлять Close() для отсрочки. Но если что-то паникует между Open() и Close(), то Close() не будет вызываться по отсрочке. - person 陈阿达; 06.03.2016
comment
Затем разделите исполнение на две части. Часть, которая выполняет модификацию файла, где вы открываете/редактируете/закрываете, и часть, где вы переименовываете. Не смешивайте все намерения в одном методе, - person Simone Carletti; 06.03.2016
comment
Спасибо за предложение. Разделить и не смешивать намерения хороший способ. - person 陈阿达; 07.03.2016

В ситуации, как в вашем образце

Возможно, вы хотите следовать этому сценарию:

  • Создайте легко идентифицируемый временный файл.
  • Напишите данные.
  • Закройте файл.
  • В случае успеха переименуйте файл.

В том случае, когда вы хотите следить за действиями системы ОС над базовыми файлами, возможно, вы хотите просто не откладывать закрытие файла IO.file, поскольку вы хотите, чтобы ошибка возвращалась самой функцией закрытия.

Кроме того, в этом случае вы, возможно, захотите также использовать file.sync().

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

person Stilmant Michael    schedule 05.12.2018