【发布时间】:2011-12-14 20:03:29
【问题描述】:
在红宝石中...
我有一个由外部进程创建的 IO 对象,我需要从中获取文件名。 但是我似乎只能获取文件描述符(3),这对我来说不是很有用。
有没有办法从这个对象中获取文件名,甚至获取一个文件对象?
我正在从通知程序获取 IO 对象。那么这可能也是获取文件路径的一种方式吗?
【问题讨论】:
在红宝石中...
我有一个由外部进程创建的 IO 对象,我需要从中获取文件名。 但是我似乎只能获取文件描述符(3),这对我来说不是很有用。
有没有办法从这个对象中获取文件名,甚至获取一个文件对象?
我正在从通知程序获取 IO 对象。那么这可能也是获取文件路径的一种方式吗?
【问题讨论】:
how to get a the filename in C上也有类似的问题,我这里用红宝石的方式给出这个问题的答案。
假设 io 是您的 IO 对象。以下代码为您提供文件名。
File.readlink("/proc/self/fd/#{io.fileno}")
这不起作用,例如,如果在为其创建 io 对象后删除了文件。使用此解决方案,您有文件名,但没有 File 对象。
IO#for_fd 方法可以创建一个 IO,它是任何给定整数文件描述符的子类。您可以通过以下方式为您的 fd 获取 File 对象:
File.for_fd(io.fileno)
不幸的是,这个 File 对象不知道文件名。
File.for_fd(io.fileno).path # => nil
我浏览了 ruby-1.9.2 源代码。在创建文件对象后,纯 ruby 似乎无法操作路径。
可以在 C 中创建对 ruby 的扩展,它首先调用 File#for_fd,然后操作文件内部数据结构。此源代码适用于 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);
}
现在你可以在编译后做:
require "./filename"
f= File.for_fd_with_filename(io.fileno, File.readlink("/proc/self/fd/#{io.fileno}"))
f.path # => the filename
也可以将读取链接放入File#for_fd_with_filename 定义中。这个例子只是为了展示它是如何工作的。
【讨论】:
/proc 伪文件系统(是的,有 procfs,但默认情况下不安装在FreeBSD——除了被淘汰——而且在 OS X 下安装绝对不是微不足道的)。
如果您确定 IO 对象代表一个文件,您可以尝试这样的操作
path = io.path if io.respond_to?(:path)
【讨论】:
File 对象 -- f.path 将返回旧路径。