duanbangzhou7809 2018-11-07 06:29
浏览 80
已采纳

如何检测已删除的文件?

Writing to a non-existent file does not produce an error in Go.

For example, here's a sample program writing to a file in a loop:

package main

import (
    "log"
    "os"
    "time"
)

func main() {

    f, err := os.OpenFile("mytest.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        log.Fatal(err)
    }

    for {

        n, err := f.WriteString("blah
")
        if err != nil {
            log.Fatal(err)
        }
        log.Printf("wrote %d bytes
", n)
        time.Sleep(2 * time.Second)
    }
}

While this is running, I issue rm mytest.log from the command line and observe that the program does not produce an error on the next call to WriteString(). (I tested on Linux, it may be different for other OS's)

Is there a way to detect if the file was deleted (other than doing a stat on the file before every write)? And presumably the bytes written are simply discarded by the operating system?

  • 写回答

1条回答 默认 最新

  • douyan1896 2018-11-07 09:48
    关注

    While this is running, I issue rm mytest.log from the command line and observe that the program does not produce an error on the next call to WriteString()

    Yes, that's exactly the behavior that's specified. Also the file hasn't been removed. The only thing that rm does remove is that particular path entry in the filesystem. A single file can have multiple paths, also called hardlinks.

    The actual file is deleted only, when the last reference to it, either by filesystem entry (link) or by file descriptor (file open in a program) has been closed.

    This particular behavior of the Unix file model was used for a long time to implement "unnamed" shared memory, by creating and opening a file in /dev/shm and then removing the filesystem entry – because this particular way of doing things introduces a race condition, for security sensitive applications new syscalls were introduced, that allow creating anonymous memory maps, and very recently Linux even got a function to create a file in a filesystem, without creating a path entry (open with O_TMPFILE flag).

    On more recent versions of Linux you can even re-/create filesystem entries for files which last entry already was removed using the linkat syscall.

    Update

    The question is, do you really want to error out if the last filesystem entry vanishes? It's not a bad condition after all, you can safely write and read, without problems, just be aware, that once you close the last file descriptor to the file, it will be lost.

    It is perfectly possible to detect if the last filesystem entry has been removed and abort file operations if so – however be aware, that such code might introduce it's very own share of problems, for example if the program expects to create a new filesystem entry, once everything has been written to the file properly, using linkat.

    Anyway, what you can do, is fstat-ing the file (file.Stat in Go) and look at the number of hardlinks the file has. If that number drops to zero, all filesystem entries are gone. Actually getting that number is a little bit tricky in Go, it's described here Counting hard links to a file in Go

    package main
    
    import (
        "fmt"
        "log"
        "os"
        "syscall"
        "time"
    )
    
    func main() {
        fmt.Println("Test Operation")
        f, err := os.OpenFile("test.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
        if err != nil {
            log.Fatal(err)
        }
    
        for {
    
            n, err := f.WriteString("blah
    ")
            if err != nil {
                log.Fatal(err)
            }
            log.Printf("wrote %d bytes
    ", n)
            time.Sleep(2 * time.Second)
            stat, err := f.Stat()
            if err != nil{
                log.Fatal(err)
            }
            if sys := stat.Sys(); sys != nil {
                if stat, ok := sys.(*syscall.Stat_t); ok {
                    nlink := uint64(stat.Nlink)
                    if 0 == nlink {
                        log.Printf("All filesystem entries to original file removed, exiting")
                        break
                    }
                }
            }
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 mmocr的训练错误,结果全为0
  • ¥15 python的qt5界面
  • ¥15 无线电能传输系统MATLAB仿真问题
  • ¥50 如何用脚本实现输入法的热键设置
  • ¥20 我想使用一些网络协议或者部分协议也行,主要想实现类似于traceroute的一定步长内的路由拓扑功能
  • ¥30 深度学习,前后端连接
  • ¥15 孟德尔随机化结果不一致
  • ¥15 apm2.8飞控罗盘bad health,加速度计校准失败
  • ¥15 求解O-S方程的特征值问题给出边界层布拉休斯平行流的中性曲线
  • ¥15 谁有desed数据集呀