How to get file name from ruby ​​input / output object

In a ruby ​​...

I have an IO object created by an external process from which I need to get the file name. However, it seems to me that I can get the file descriptor (3), which is not very useful to me.

Is there a way to get the file name from this object or even get the file file?

I get an IO object from the notifier. So this could be a way to get the file path?

+6
source share
2 answers

There is a similar question about how to get the file name in C , I will present here the answer to this question in a ruby ​​way.

Getting the file name in Linux

Suppose io is your input / output object. The following code gives you the file name.

 File.readlink("/proc/self/fd/#{io.fileno}") 

This does not work, for example, if the file was deleted after the creation of the io object. With this solution, you have a file name, but not a File object.

Getting a File Object That Does Not Know the File Name

The IO#for_fd can create IO and its subclasses for any given integer filedescriptor. Get your File object for your fd by doing the following:

 File.for_fd(io.fileno) 

Unfortunately, this File object does not know the file name.

 File.for_fd(io.fileno).path # => nil 

I looked at ruby-1.9.2 sources. There seems to be no way in a pure ruby ​​to manipulate a path after creating a file object.

Getting a File object that knows the file name

An extension to ruby ​​can be created in C, which first calls File#for_fd and then processes the internal data structures of Files. This source code works for ruby-1.9.2, for other versions of ruby ​​it can be configured.

 #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); } 

Now you can do it after compilation:

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

A reading link can also be placed in the definition of File#for_fd_with_filename . These examples are just to show how it works.

+5
source

If you are sure that the IO object represents the file, you can try something like this

 path = io.path if io.respond_to?(:path) 

See the documentation for the path File #

0
source

Source: https://habr.com/ru/post/900030/


All Articles