Go語(yǔ)言是一門(mén)強(qiáng)大的編程語(yǔ)言,但在處理文件操作時(shí)可能會(huì)遇到一些問(wèn)題。特別是當(dāng)程序A打開(kāi)一個(gè)文件時(shí),程序B可能會(huì)嘗試對(duì)該文件進(jìn)行歸檔或刪除,這可能導(dǎo)致程序A出現(xiàn)錯(cuò)誤。php小編西瓜在這里給出一些方法,幫助您在Go語(yǔ)言中防止程序B對(duì)程序A當(dāng)前打開(kāi)的文件進(jìn)行操作,確保程序的穩(wěn)定運(yùn)行。下面是一些解決方案:
問(wèn)題內(nèi)容
編程語(yǔ)言:使用最新版本
我正在開(kāi)發(fā)一個(gè)程序 A,它需要將日志文件歸檔到一個(gè)目錄中,不包括由程序 B 打開(kāi)的日志文件,該程序使用它來(lái)進(jìn)行日志記錄。打開(kāi)的文件將在特定持續(xù)時(shí)間(例如 24 小時(shí))后關(guān)閉,然后可用于存檔。顯然,兩個(gè)程序都是獨(dú)立運(yùn)行的。
當(dāng)前的實(shí)現(xiàn)不會(huì)檢查程序 B 中的文件是否打開(kāi),因?yàn)槲易罱l(fā)現(xiàn)它正在歸檔打開(kāi)的日志文件,我認(rèn)為它不會(huì)這樣做;基本上,它將文件復(fù)制到存檔并刪除它。
在嘗試歸檔文件之前檢查文件當(dāng)前是否已被另一個(gè) Go 程序打開(kāi)的可靠方法是什么?
我已經(jīng)編寫(xiě)了歸檔器,但我不會(huì)將其發(fā)布在這里,因?yàn)闆](méi)有與問(wèn)題無(wú)關(guān)的代碼,因此我只添加執(zhí)行歸檔和刪除的代碼。
我嘗試過(guò)使用 Open 和 OpenFile 函數(shù),但沒(méi)有成功。
func zipFile(filename string) error { file, err := os.Open(filename) if err != nil { return err } defer func(file *os.File) { err = file.Close() if err != nil { fmt.Println(err) } }(file) fileInfo, err := file.Stat() if err != nil { return err } archiveFile, err := os.Create(fmt.Sprintf("%s.zip", filename)) if err != nil { return err } defer func(archiveFile *os.File) { err = archiveFile.Close() if err != nil { fmt.Println(err) } }(archiveFile) zipWriter := zip.NewWriter(archiveFile) if err != nil { return err } defer func(zipWriter *zip.Writer) { err = zipWriter.Close() if err != nil { fmt.Println(err) } }(zipWriter) writer, err := zipWriter.Create(fileInfo.Name()) if err != nil { return err } _, err = io.Copy(writer, file) if err != nil { return err } err = os.Remove(filename) if err != nil { return err } fmt.Println(fmt.Sprintf("file %s was zipped", fileInfo.Name())) return nil }
登錄后復(fù)制
解決方法
無(wú)論進(jìn)程如何,了解某個(gè)文件是否被另一個(gè)進(jìn)程打開(kāi)的問(wèn)題都非常依賴于底層操作系統(tǒng)。因此,沒(méi)有通用的跨平臺(tái)方法來(lái)回答這個(gè)問(wèn)題。對(duì)于 *NIX 系統(tǒng)(Unix、Linux、macOS),回答問(wèn)題的最佳方法是使用核心 util lsof
(“列出打開(kāi)的文件”)。
在 macOS 上,看起來(lái)像這樣:
package main import ( "fmt" "os/exec" "strings" ) func main() { out, _ := exec.Command("lsof").Output() for _, line := range strings.Split(string(out), "\n") { // Skip anything that's not a regular file if !strings.Contains(line, "REG") { continue } fields := strings.Fields(line) // The macOS lsof command has the filename in the ninth field fmt.Println(fields[8]) } }
登錄后復(fù)制
或者,您可以找到一個(gè)對(duì)此進(jìn)行抽象的庫(kù),例如:https://github.com/車(chē)輪綜合體/lsof
有關(guān) lsof
的更多信息:https://www.php.cn/link/fa2246fa0fdf0d3e270c86767b77ba1b