如何从ruby中的IO对象获取文件名

Yul*_*ule 6 ruby io

在红宝石......

我有一个由外部进程创建的IO对象,我需要从中获取文件名.但是我似乎只能得到文件描述符(3),这对我来说不是很有用.

有没有办法从这个对象获取文件名甚至获取文件对象?

我从通知程序获取IO对象.所以这可能是一种获取文件路径的方法?

joh*_*nes 6

有关如何在C中获取文件名的类似问题,我将以红宝石的方式呈现此问题的答案.

在Linux中获取文件名

假设io是你的IO对象.以下代码为您提供了文件名.

File.readlink("/proc/self/fd/#{io.fileno}")
Run Code Online (Sandbox Code Playgroud)

例如,如果在为其创建io对象后删除了文件,则这不起作用.使用此解决方案,您可以使用文件名,但不能使用File对象.

获取不知道文件名的File对象

该方法IO#for_fd可以为任何给定的整数文件描述符创建IO及其子类.通过执行以下操作,获取fd的File对象:

File.for_fd(io.fileno)
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个File对象不知道文件名.

File.for_fd(io.fileno).path # => nil
Run Code Online (Sandbox Code Playgroud)

我浏览了ruby-1.9.2来源.在创建文件对象之后,纯ruby中似乎无法操纵路径.

获取知道文件名的File对象

可以在C中创建ruby的扩展,它首先调用File#for_fd并随后操作Files内部数据结构.这个源代码适用于ruby-1.9.2,对于其他版本的ruby,它可能必须调整.

#include "ruby.h"
#include "ruby/io.h"

VALUE file_fd_filename(VALUE self, VALUE fd, VALUE filename) {
    VALUE file= rb_funcall3(self, rb_intern("for_fd"), 1, &fd);
    rb_io_t *fptr= RFILE(rb_io_taint_check(file))->fptr;
    fptr->pathv= rb_str_dup(filename);
    return file;
}

void Init_filename() {

    rb_define_singleton_method(rb_cFile, "for_fd_with_filename", file_fd_filename, 2);

}
Run Code Online (Sandbox Code Playgroud)

现在你可以在编译后做:

require "./filename"
f= File.for_fd_with_filename(io.fileno, File.readlink("/proc/self/fd/#{io.fileno}"))
f.path # => the filename
Run Code Online (Sandbox Code Playgroud)

readlink也可以放入File#for_fd_with_filenamedefiniton.这个例子只是为了说明它是如何工作的.