Виртуальный файл Golang

#hadoop #go #named-pipes #fuse

#hadoop #Вперед #именованные каналы #предохранитель

Вопрос:

У меня есть закрытое приложение soruce, которое принимает файл в качестве входных данных, вычисляет его хэш и выполняет некоторые другие действия, которые я не могу контролировать. Изменение исходного кода или обратный инжиниринг невозможны.

Программа предназначена для работы с обычными файлами, однако мне нужно предоставить очень большой файл из HDFS. Копирование файла займет слишком много времени и места на диске. Итак, я думал об использовании 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)
}
  

Я знаю, что приведенный выше код неполон, тестовый файл составляет 10 МБ, однако после чтения 8 раз 4096 байт именованный буфер канала заполняется, а другая программа берет все это и закрывает канал.

Но через некоторое время другая программа, которая считывает канал, закрывает канал, и я получаю ошибку неработающего канала. Есть ли какая-либо возможность создания виртуального файла, отличного от fuse и pipe?

Ответ №1:

Я думаю, что у вас действительно была правильная идея с FUSE. Без исходных текстов для вашего вышестоящего приложения трудно сказать, какую файловую семантику оно пытается использовать (хотя некоторое время со strace может помочь прояснить, что происходит. Может быть …).

В любом случае, я бы взглянул на проект Go-FUSE, в частности на пример hello.go, который точно показывает, как очень хорошо обрабатывать случай с одним файлом.

Ответ №2:

Я понимаю, проблема в том, что программа с закрытым исходным кодом2 ожидает имя файла и не принимает ввод непосредственно из stdin?

Вы можете использовать стандартный конвейер в стиле Unix при запуске программ для соединения stdin и stdout процессов вместе. Именованные каналы могут быть проблематичными, и использование FUSE для этого слишком сложно.

Вы могли бы настроить вывод вашей программы1 в стандартный вывод. и укажите программе с закрытым исходным кодом2 имя виртуального файла /dev/stdin следующим образом:

 program1 | program2 /dev/stdin
  

Предполагается, что вы работаете в Linux (вы не указали, но я предполагаю, что это так, потому что вы говорите о FUSE).

Если program2 заботится об имени файла (например, ожидает определенного расширения имени), вы могли бы обойти это, создав символическую ссылку с желаемым именем, указывающим на /dev/stdin , и указав имя символической ссылки в качестве аргумента для program2:

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

Ничего из этого не сработает, если program2 ожидает реального файла, который он может stat, но в данном случае это не должно быть проблемой (как известно из вопроса, что program2 принимает именованный канал).

Также, если program2 ожидает ввода с клавиатуры из stdin, этот подход не будет работать.