Golang 虚拟文件

Golang Virtual File

我有一个封闭的 source 应用程序,它将一个文件作为输入,计算它的哈希值并做一些我无法控制的其他事情。修改源代码或逆向工程是不可行的。

该程序旨在处理常规文件,但我需要从 HDFS 提供一个非常大的文件。复制文件将花费太多时间,并且 space 占用磁盘空间。所以一直在想用FUSE,但是没找到好的解决办法。我尝试使用命名管道如下:

func readFile(namenode, path string, pipe *os.File) {
    client, err := hdfs.New(namenode)
    log.Println(err, client)

    hdfsFile, err := client.Open(path)
    if err != nil {
        log.Fatal(err)
    }
    log.Println(hdfsFile)

    // written, err := io.Copy(pipe, hdfsFile)
    bytes := make([]byte, 4096)
    for {
        read, err := hdfsFile.Read(bytes)
        log.Println(read, err)
        if err != nil {
            break
        }
        written, err := pipe.Write(bytes)
        log.Println(written, err)
    }
    err = pipe.Close()
    log.Println(err)
}

我知道上面的代码不完整,测试文件是 10MB,但是在读取 8 次后,4096 字节的命名管道缓冲区变满,另一个程序将其全部占用并关闭管道。

但是过了一会儿,另一个正在读取管道的程序关闭了管道,我得到了管道损坏的错误。是否可以创建除 fuse 和 pipe 之外的虚拟文件?

我认为您对 FUSE 的想法是正确的。如果没有上游应用程序的源代码,很难说出它试图使用什么文件语义(尽管使用 strace 的一些时间可能有助于阐明正在发生的事情。也许......)。

无论如何,我都会看一下 the Go-FUSE project, specifically the hello.go example,它准确地展示了如何很好地处理单个文件的情况。

我明白这个问题是闭源程序 2 需要一个文件名并且不接受直接来自 stdin?

的输入

当 运行 程序连接 stdinstdout 时,您可以使用标准 Unix 风格的管道一起处理。命名管道可能会有问题,为此使用 FUSE 过于复杂。

您可以让您的程序 1 输出到 stdout。并为闭源程序 2 提供虚拟文件名 /dev/stdin,如下所示:

program1 | program2 /dev/stdin

这是假设您正在研究 Linux(您没有指定但我假设是因为您在谈论 FUSE)。

如果 program2 关心文件名(例如需要特定的扩展名),您可以通过创建符号 link 并将所需名称指向 /dev/stdin 来解决这个问题并提供符号 link 的名称作为 program2:

的参数
ln -s /dev/stdin file.ext
program1 | program2 file.ext
rm -f file.ext

None 如果 program2 需要一个它可以 stat 的真实文件,那么它的

None 将起作用,但在这种情况下,这应该不是问题(因为从program2 接受命名管道的问题)。

此外,如果程序 2 需要来自 stdin 的键盘输入,这种方法将不起作用。