编程语言:GO最新版本

我正在处理一个程序A,它需要将日志(log)文件归档到一个目录中,但不包括由使用它进行日志(log)记录的程序B打开的那个目录.打开的文件将在特定持续时间后关闭,比方说24小时,然后可用于存档.显然,这两个程序都是独立运行的.

目前的实现不判断文件是否在程序B中打开,因为我最近发现它正在存档打开的日志(log)文件,我假设它不会这样做;基本上它将文件复制到存档中并删除它.

What would be a reliable way to check if a file is currently opened by another Go program before attempting to archive it?

我已经编写了归档程序,但我不会在这里发布它,因为问题没有相关的代码,所以我只添加了执行归档和删除的代码.

我已经try 了Open和OpenFile两个功能,但都没有成功.

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
}

推荐答案

知道某个文件是否被另一个进程打开的问题非常依赖于底层操作系统,而不管该进程是什么.因此,没有通用的、跨平台的方法来回答这个问题.对于*NIX系统(Unix、Linux、MacOS),回答这个问题的最好方法是使用核心util lsof("列出打开的文件").

在MacOS上,这看起来像这样:

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

或者,您可以找到一个库来抽象这一点,如下所示:https://github.com/wheelcomplex/lsof

更多关于lsof:https://en.wikipedia.org/wiki/Lsof的内容

Go相关问答推荐

如何创建两个连接的io.ReadWriteClosers以用于测试目的

GORM Find方法中缺少字段

使用一元或服务器流将切片从GRPC服务器返回到客户端

Redis:尽管数据存在,但 rdb.Pipelined 中出现redis:nil错误

如何确定泛型类型在运行时是否可比较?

如何在 Chi Router 的受保护路由下提供静态文件(尤其是图像)?

是否需要手动调用rand.Seed?

Golang和Gin web框架在router.Run()之后执行代码

如何将字节文件高效地读入int64切片?

由于 main.go 文件中的本地包导入导致构建 docker 容器时出错

如何在 `hashicorp / terraform-exec` 中将 `ApplyConfig` 传递给 `tf.Apply()`?

将文本文件放入切片然后进行比较

使用图像解码 JPEG 时 colored颜色 不正确.解码并写入 PDF?

CBC Decrypter 解密加密文本,但部分文本被随机字符替换

如何将具有嵌入式 struct 的 struct 展平为 json

如何将多个切片打印为一个切片?

try 与 golang testify/suite 并行运行测试失败

我该如何做错误处理惯用的方式

Go/Golang:如何从 big.Float 中提取最低有效数字?

Go generics:我会在哪里使用 any 而不是 interface{}?