类 Pathname

Pathname 表示文件系统中文件或目录的名称,但不表示文件本身。

路径名取决于操作系统:Unix、Windows 等。此库适用于本地操作系统的路径名,但实验性地支持非 Unix 路径名。

Pathname 可以是相对路径或绝对路径。只有在你尝试引用文件时,它才会关心文件是否存在。

Pathname 是不可变的。它没有用于破坏性更新的方法。

此类的目标是以比标准 Ruby 提供的更简洁的方式操作文件路径信息。以下示例演示了差异。

所有来自 FileFileTest 以及部分来自 DirFileUtils 的功能都以一种不令人意外的方式包含在内。它本质上是所有这些功能的 фасадом,以及更多。

示例

示例 1:使用 Pathname

require 'pathname'
pn = Pathname.new("/usr/bin/ruby")
size = pn.size              # 27662
isdir = pn.directory?       # false
dir  = pn.dirname           # Pathname:/usr/bin
base = pn.basename          # Pathname:ruby
dir, base = pn.split        # [Pathname:/usr/bin, Pathname:ruby]
data = pn.read
pn.open { |f| _ }
pn.each_line { |line| _ }

示例 2:使用标准 Ruby

pn = "/usr/bin/ruby"
size = File.size(pn)        # 27662
isdir = File.directory?(pn) # false
dir  = File.dirname(pn)     # "/usr/bin"
base = File.basename(pn)    # "ruby"
dir, base = File.split(pn)  # ["/usr/bin", "ruby"]
data = File.read(pn)
File.open(pn) { |f| _ }
File.foreach(pn) { |line| _ }

示例 3:特殊功能

p1 = Pathname.new("/usr/lib")   # Pathname:/usr/lib
p2 = p1 + "ruby/1.8"            # Pathname:/usr/lib/ruby/1.8
p3 = p1.parent                  # Pathname:/usr
p4 = p2.relative_path_from(p3)  # Pathname:lib/ruby/1.8
pwd = Pathname.pwd              # Pathname:/home/gavin
pwd.absolute?                   # true
p5 = Pathname.new "."           # Pathname:.
p5 = p5 + "music/../articles"   # Pathname:music/../articles
p5.cleanpath                    # Pathname:articles
p5.realpath                     # Pathname:/home/gavin/articles
p5.children                     # [Pathname:/home/gavin/articles/linux, ...]

功能分解

核心方法

这些方法实际上是在操作一个 String,因为路径本质上就是一个字符串。除了 mountpoint?childreneach_childrealdirpathrealpath 之外,这些方法都不会访问文件系统。

File 状态谓词方法

这些方法是 FileTest 的 фасадом

File 属性和操作方法

这些方法是 File 的外观

目录方法

这些方法是 Dir 的外观

IO

这些方法是 IO 的外观

实用程序

这些方法是 FindFileUtils 和其他方法的混合

Method 文档

如上节所示,Pathname 中的大多数方法都是外观。这些方法的文档通常只说,例如,“参见 FileTest.writable?”,因为您应该已经熟悉原始方法,并且它的文档(例如通过 ri)将包含更多信息。在某些情况下,将简要描述。

常量

版本

公共类方法

getwd() 点击切换源代码

返回当前工作目录作为 Pathname 对象。

Pathname.getwd
    #=> #<Pathname:/home/zzak/projects/ruby>

参见 Dir.getwd

static VALUE
path_s_getwd(VALUE klass)
{
    VALUE str;
    str = rb_funcall(rb_cDir, id_getwd, 0);
    return rb_class_new_instance(1, &str, klass);
}
glob(p1, p2 = v2, p3 = v3) 点击切换源代码

返回或生成 Pathname 对象。

Pathname.glob("lib/i*.rb")
    #=> [#<Pathname:lib/ipaddr.rb>, #<Pathname:lib/irb.rb>]

参见 Dir.glob

static VALUE
path_s_glob(int argc, VALUE *argv, VALUE klass)
{
    VALUE args[3];
    int n;

    n = rb_scan_args(argc, argv, "12", &args[0], &args[1], &args[2]);
    if (rb_block_given_p()) {
        return rb_block_call_kw(rb_cDir, id_glob, n, args, s_glob_i, klass, RB_PASS_CALLED_KEYWORDS);
    }
    else {
        VALUE ary;
        long i;
        ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_CALLED_KEYWORDS);
        ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
        for (i = 0; i < RARRAY_LEN(ary); i++) {
            VALUE elt = RARRAY_AREF(ary, i);
            elt = rb_class_new_instance(1, &elt, klass);
            rb_ary_store(ary, i, elt);
        }
        return ary;
    }
}
new(p1) 点击切换源代码

从给定的 String(或类似字符串的对象)创建 Pathname 对象。如果 path 包含空字符 (\0),则会引发 ArgumentError 错误。

static VALUE
path_initialize(VALUE self, VALUE arg)
{
    VALUE str;
    if (RB_TYPE_P(arg, T_STRING)) {
        str = arg;
    }
    else {
        str = rb_check_funcall(arg, id_to_path, 0, NULL);
        if (str == Qundef)
            str = arg;
        StringValue(str);
    }
    if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str)))
        rb_raise(rb_eArgError, "pathname contains null byte");
    str = rb_obj_dup(str);

    set_strpath(self, str);
    return self;
}
pwd() 点击切换源代码

返回当前工作目录作为 Pathname 对象。

Pathname.getwd
    #=> #<Pathname:/home/zzak/projects/ruby>

参见 Dir.getwd

static VALUE
path_s_getwd(VALUE klass)
{
    VALUE str;
    str = rb_funcall(rb_cDir, id_getwd, 0);
    return rb_class_new_instance(1, &str, klass);
}

公共实例方法

+(other) 点击切换源代码

将路径片段附加到 self 以生成新的 Pathname 对象。由于 other 被视为相对于 self 的路径,如果 other 是绝对路径,则新的 Pathname 对象将仅从 other 创建。

p1 = Pathname.new("/usr")      # Pathname:/usr
p2 = p1 + "bin/ruby"           # Pathname:/usr/bin/ruby
p3 = p1 + "/etc/passwd"        # Pathname:/etc/passwd

# / is aliased to +.
p4 = p1 / "bin/ruby"           # Pathname:/usr/bin/ruby
p5 = p1 / "/etc/passwd"        # Pathname:/etc/passwd

此方法不会访问文件系统;它只是纯字符串操作。

# File ext/pathname/lib/pathname.rb, line 356
def +(other)
  other = Pathname.new(other) unless Pathname === other
  Pathname.new(plus(@path, other.to_s))
end
别名:/
/(other)
别名:+
<=>(p1) 点击切换源代码

提供路径名的区分大小写的比较运算符。

Pathname.new('/usr') <=> Pathname.new('/usr/bin')
    #=> -1
Pathname.new('/usr/bin') <=> Pathname.new('/usr/bin')
    #=> 0
Pathname.new('/usr/bin') <=> Pathname.new('/USR/BIN')
    #=> 1

它将根据左侧参数相对于右侧参数的值返回 -101。或者,如果参数不可比较,则返回 nil

static VALUE
path_cmp(VALUE self, VALUE other)
{
    VALUE s1, s2;
    char *p1, *p2;
    char *e1, *e2;
    if (!rb_obj_is_kind_of(other, rb_cPathname))
        return Qnil;
    s1 = get_strpath(self);
    s2 = get_strpath(other);
    p1 = RSTRING_PTR(s1);
    p2 = RSTRING_PTR(s2);
    e1 = p1 + RSTRING_LEN(s1);
    e2 = p2 + RSTRING_LEN(s2);
    while (p1 < e1 && p2 < e2) {
        int c1, c2;
        c1 = (unsigned char)*p1++;
        c2 = (unsigned char)*p2++;
        if (c1 == '/') c1 = '\0';
        if (c2 == '/') c2 = '\0';
        if (c1 != c2) {
            if (c1 < c2)
                return INT2FIX(-1);
            else
                return INT2FIX(1);
        }
    }
    if (p1 < e1)
        return INT2FIX(1);
    if (p2 < e2)
        return INT2FIX(-1);
    return INT2FIX(0);
}
==(p1) 点击切换源代码

将此路径名与 other 进行比较。比较是基于字符串的。请注意,两个不同的路径 (foo.txt./foo.txt) 可以引用同一个文件。

static VALUE
path_eq(VALUE self, VALUE other)
{
    if (!rb_obj_is_kind_of(other, rb_cPathname))
        return Qfalse;
    return rb_str_equal(get_strpath(self), get_strpath(other));
}
别名:===eql?
===(p1)

将此路径名与 other 进行比较。比较是基于字符串的。请注意,两个不同的路径 (foo.txt./foo.txt) 可以引用同一个文件。

别名:==
absolute?() 点击切换源代码

用于测试路径是否为绝对路径的谓词方法。

如果路径名以斜杠开头,则返回true

p = Pathname.new('/im/sure')
p.absolute?
    #=> true

p = Pathname.new('not/so/sure')
p.absolute?
    #=> false
# File ext/pathname/lib/pathname.rb, line 233
def absolute?
  ABSOLUTE_PATH.match? @path
end
ascend() { |self| ... } 点击切换源代码

按升序遍历给定路径中的每个元素,并为每个元素生成一个新的Pathname对象。

Pathname.new('/path/to/some/file.rb').ascend {|v| p v}
   #<Pathname:/path/to/some/file.rb>
   #<Pathname:/path/to/some>
   #<Pathname:/path/to>
   #<Pathname:/path>
   #<Pathname:/>

Pathname.new('path/to/some/file.rb').ascend {|v| p v}
   #<Pathname:path/to/some/file.rb>
   #<Pathname:path/to/some>
   #<Pathname:path/to>
   #<Pathname:path>

如果没有给出代码块,则返回一个Enumerator

enum = Pathname.new("/usr/bin/ruby").ascend
  # ... do stuff ...
enum.each { |e| ... }
  # yields Pathnames /usr/bin/ruby, /usr/bin, /usr, and /.

它不会访问文件系统。

# File ext/pathname/lib/pathname.rb, line 330
def ascend
  return to_enum(__method__) unless block_given?
  path = @path
  yield self
  while r = chop_basename(path)
    path, = r
    break if path.empty?
    yield self.class.new(del_trailing_separator(path))
  end
end
atime → time 点击切换源代码

返回文件的最后访问时间。

参见File.atime

static VALUE
path_atime(VALUE self)
{
    return rb_funcall(rb_cFile, id_atime, 1, get_strpath(self));
}
basename(p1 = v1) 点击切换源代码

返回路径的最后一个组件。

参见File.basename

static VALUE
path_basename(int argc, VALUE *argv, VALUE self)
{
    VALUE str = get_strpath(self);
    VALUE fext;
    if (rb_scan_args(argc, argv, "01", &fext) == 0)
        str = rb_funcall(rb_cFile, id_basename, 1, str);
    else
        str = rb_funcall(rb_cFile, id_basename, 2, str, fext);
    return rb_class_new_instance(1, &str, rb_obj_class(self));
}
binread([length [, offset]]) → string 点击切换源代码

返回文件中的所有字节,或者如果指定了,则返回前N个字节。

参见File.binread

static VALUE
path_binread(int argc, VALUE *argv, VALUE self)
{
    VALUE args[3];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
    return rb_funcallv(rb_cFile, id_binread, 1+n, args);
}
binwrite(string, [offset] ) → fixnum 点击切换源代码
binwrite(string, [offset], open_args ) → fixnum

contents写入文件,以二进制模式打开它。

参见File.binwrite

static VALUE
path_binwrite(int argc, VALUE *argv, VALUE self)
{
    VALUE args[4];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
    return rb_funcallv_kw(rb_cFile, id_binwrite, 1+n, args, RB_PASS_CALLED_KEYWORDS);
}
birthtime → time 点击切换源代码

返回文件的创建时间。如果平台没有创建时间,则会引发NotImplementedError

参见File.birthtime

static VALUE
path_birthtime(VALUE self)
{
    return rb_funcall(rb_cFile, id_birthtime, 1, get_strpath(self));
}
blockdev?() 点击切换源代码

参见FileTest.blockdev?

static VALUE
path_blockdev_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_blockdev_p, 1, get_strpath(self));
}
chardev?() 点击切换源代码

参见FileTest.chardev?

static VALUE
path_chardev_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_chardev_p, 1, get_strpath(self));
}
children(with_directory=true) 点击切换源代码

返回目录的子项(文件和子目录,非递归),作为Pathname对象的数组。

默认情况下,返回的路径名将包含访问文件所需的信息。如果将with_directory设置为false,则返回的路径名将仅包含文件名。

例如

pn = Pathname("/usr/lib/ruby/1.8")
pn.children
    # -> [ Pathname:/usr/lib/ruby/1.8/English.rb,
           Pathname:/usr/lib/ruby/1.8/Env.rb,
           Pathname:/usr/lib/ruby/1.8/abbrev.rb, ... ]
pn.children(false)
    # -> [ Pathname:English.rb, Pathname:Env.rb, Pathname:abbrev.rb, ... ]

请注意,结果中永远不会包含目录中的条目 ...,因为它们不是子项。

# File ext/pathname/lib/pathname.rb, line 449
def children(with_directory=true)
  with_directory = false if @path == '.'
  result = []
  Dir.foreach(@path) {|e|
    next if e == '.' || e == '..'
    if with_directory
      result << self.class.new(File.join(@path, e))
    else
      result << self.class.new(e)
    end
  }
  result
end
chmod(mode_int) → integer 点击切换源代码

更改文件权限。

参见 File.chmod.

static VALUE
path_chmod(VALUE self, VALUE mode)
{
    return rb_funcall(rb_cFile, id_chmod, 2, mode, get_strpath(self));
}
chown(owner_int, group_int) → integer 点击切换源代码

更改文件的拥有者和组。

参见 File.chown.

static VALUE
path_chown(VALUE self, VALUE owner, VALUE group)
{
    return rb_funcall(rb_cFile, id_chown, 3, owner, group, get_strpath(self));
}
cleanpath(consider_symlink=false) 点击切换源代码

返回 self 的干净路径名,其中连续的斜杠和无用的点已删除。不会访问文件系统。

如果 consider_symlinktrue,则使用更保守的算法来避免破坏符号链接。这可能会保留比绝对必要更多的 .. 条目,但在不访问文件系统的情况下,这是无法避免的。

参见 Pathname#realpath.

# File ext/pathname/lib/pathname.rb, line 94
def cleanpath(consider_symlink=false)
  if consider_symlink
    cleanpath_conservative
  else
    cleanpath_aggressive
  end
end
ctime → time 点击切换源代码

返回最后修改时间,使用目录信息,而不是文件本身。

参见 File.ctime.

static VALUE
path_ctime(VALUE self)
{
    return rb_funcall(rb_cFile, id_ctime, 1, get_strpath(self));
}
delete()

删除文件或目录,如果 self 是文件,则使用 File.unlink,或者根据需要使用 Dir.unlink

别名:unlink
descend() { |v| ... } 点击切换源代码

以降序迭代并生成给定路径中每个元素的新的 Pathname 对象。

Pathname.new('/path/to/some/file.rb').descend {|v| p v}
   #<Pathname:/>
   #<Pathname:/path>
   #<Pathname:/path/to>
   #<Pathname:/path/to/some>
   #<Pathname:/path/to/some/file.rb>

Pathname.new('path/to/some/file.rb').descend {|v| p v}
   #<Pathname:path>
   #<Pathname:path/to>
   #<Pathname:path/to/some>
   #<Pathname:path/to/some/file.rb>

如果没有给出代码块,则返回一个Enumerator

enum = Pathname.new("/usr/bin/ruby").descend
  # ... do stuff ...
enum.each { |e| ... }
  # yields Pathnames /, /usr, /usr/bin, and /usr/bin/ruby.

它不会访问文件系统。

# File ext/pathname/lib/pathname.rb, line 297
def descend
  return to_enum(__method__) unless block_given?
  vs = []
  ascend {|v| vs << v }
  vs.reverse_each {|v| yield v }
  nil
end
directory?() 点击切换源代码

参见 FileTest.directory?.

static VALUE
path_directory_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_directory_p, 1, get_strpath(self));
}
dirname() 点击切换源代码

返回路径中除最后一个组件之外的所有组件。

参见 File.dirname.

static VALUE
path_dirname(VALUE self)
{
    VALUE str = get_strpath(self);
    str = rb_funcall(rb_cFile, id_dirname, 1, str);
    return rb_class_new_instance(1, &str, rb_obj_class(self));
}
each_child(with_directory=true, &b) 点击切换源代码

迭代目录的子项(文件和子目录,非递归)。

它为每个子项生成 Pathname 对象。

默认情况下,生成的路径名将包含足够的信息来访问文件。

如果将 with_directory 设置为 false,则返回的路径名将仅包含文件名。

Pathname("/usr/local").each_child {|f| p f }
#=> #<Pathname:/usr/local/share>
#   #<Pathname:/usr/local/bin>
#   #<Pathname:/usr/local/games>
#   #<Pathname:/usr/local/lib>
#   #<Pathname:/usr/local/include>
#   #<Pathname:/usr/local/sbin>
#   #<Pathname:/usr/local/src>
#   #<Pathname:/usr/local/man>

Pathname("/usr/local").each_child(false) {|f| p f }
#=> #<Pathname:share>
#   #<Pathname:bin>
#   #<Pathname:games>
#   #<Pathname:lib>
#   #<Pathname:include>
#   #<Pathname:sbin>
#   #<Pathname:src>
#   #<Pathname:man>

请注意,结果中永远不会包含目录中的条目 ...,因为它们不是子项。

参见 Pathname#children

# File ext/pathname/lib/pathname.rb, line 499
def each_child(with_directory=true, &b)
  children(with_directory).each(&b)
end
each_entry() 点击切换源代码

遍历目录中的条目(文件和子目录),为每个条目生成一个 Pathname 对象。

static VALUE
path_each_entry(VALUE self)
{
    VALUE args[1];
    RETURN_ENUMERATOR(self, 0, 0);

    args[0] = get_strpath(self);
    return rb_block_call(rb_cDir, id_foreach, 1, args, each_entry_i, rb_obj_class(self));
}
each_filename() { |filename| ... } 点击切换源代码

遍历路径的每个组件。

Pathname.new("/usr/bin/ruby").each_filename {|filename| ... }
  # yields "usr", "bin", and "ruby".

如果没有给出代码块,则返回一个Enumerator

enum = Pathname.new("/usr/bin/ruby").each_filename
  # ... do stuff ...
enum.each { |e| ... }
  # yields "usr", "bin", and "ruby".
# File ext/pathname/lib/pathname.rb, line 265
def each_filename # :yield: filename
  return to_enum(__method__) unless block_given?
  _, names = split_names(@path)
  names.each {|filename| yield filename }
  nil
end
each_line {|line| ... } 点击切换源代码
each_line(sep=$/ [, open_args]) {|line| block } → nil
each_line(limit [, open_args]) {|line| block } → nil
each_line(sep, limit [, open_args]) {|line| block } → nil
each_line(...) → an_enumerator

遍历文件中的每一行,为每一行生成一个 String 对象。

static VALUE
path_each_line(int argc, VALUE *argv, VALUE self)
{
    VALUE args[4];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
    if (rb_block_given_p()) {
        return rb_block_call_kw(rb_cFile, id_foreach, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
    }
    else {
        return rb_funcallv_kw(rb_cFile, id_foreach, 1+n, args, RB_PASS_CALLED_KEYWORDS);
    }
}
empty?() 点击切换源代码

测试文件是否为空。

参见 Dir#empty? 和 FileTest.empty?

static VALUE
path_empty_p(VALUE self)
{

    VALUE path = get_strpath(self);
    if (RTEST(rb_funcall(rb_mFileTest, id_directory_p, 1, path)))
        return rb_funcall(rb_cDir, id_empty_p, 1, path);
    else
        return rb_funcall(rb_mFileTest, id_empty_p, 1, path);
}
entries() 点击切换源代码

返回目录中的条目(文件和子目录),每个条目都是一个 Pathname 对象。

结果只包含目录中的名称,不包含任何尾部斜杠或递归查找。

pp Pathname.new('/usr/local').entries
#=> [#<Pathname:share>,
#    #<Pathname:lib>,
#    #<Pathname:..>,
#    #<Pathname:include>,
#    #<Pathname:etc>,
#    #<Pathname:bin>,
#    #<Pathname:man>,
#    #<Pathname:games>,
#    #<Pathname:.>,
#    #<Pathname:sbin>,
#    #<Pathname:src>]

结果可能包含当前目录 #<Pathname:.> 和父目录 #<Pathname:..>

如果您不想要 ... 并且想要目录,请考虑使用 Pathname#children

static VALUE
path_entries(VALUE self)
{
    VALUE klass, str, ary;
    long i;
    klass = rb_obj_class(self);
    str = get_strpath(self);
    ary = rb_funcall(rb_cDir, id_entries, 1, str);
    ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        VALUE elt = RARRAY_AREF(ary, i);
        elt = rb_class_new_instance(1, &elt, klass);
        rb_ary_store(ary, i, elt);
    }
    return ary;
}
eql?(p1)

将此路径名与 other 进行比较。比较是基于字符串的。请注意,两个不同的路径 (foo.txt./foo.txt) 可以引用同一个文件。

别名:==
executable?() 点击切换源代码

参见 FileTest.executable?

static VALUE
path_executable_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_executable_p, 1, get_strpath(self));
}
executable_real?() 点击切换源代码

参见 FileTest.executable_real?

static VALUE
path_executable_real_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_executable_real_p, 1, get_strpath(self));
}
exist?() 点击切换源代码

参见 FileTest.exist?

static VALUE
path_exist_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_exist_p, 1, get_strpath(self));
}
expand_path(p1 = v1) 点击切换源代码

返回文件的绝对路径。

参见 File.expand_path

static VALUE
path_expand_path(int argc, VALUE *argv, VALUE self)
{
    VALUE str = get_strpath(self);
    VALUE dname;
    if (rb_scan_args(argc, argv, "01", &dname) == 0)
        str = rb_funcall(rb_cFile, id_expand_path, 1, str);
    else
        str = rb_funcall(rb_cFile, id_expand_path, 2, str, dname);
    return rb_class_new_instance(1, &str, rb_obj_class(self));
}
extname() 点击切换源代码

返回文件的扩展名。

参见 File.extname

static VALUE
path_extname(VALUE self)
{
    VALUE str = get_strpath(self);
    return rb_funcall(rb_cFile, id_extname, 1, str);
}
file?() 点击切换源代码

参见 FileTest.file?

static VALUE
path_file_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_file_p, 1, get_strpath(self));
}
find(ignore_error: true) { |pathname| ... } 点击切换源代码

以深度优先的方式遍历目录树,为“此”目录下的每个文件生成一个 Pathname 对象。

如果没有给出代码块,则返回一个 Enumerator 对象。

由于它是通过标准库模块 Find 实现的,因此可以使用 Find.prune 来控制遍历。

如果 self.,则生成的路径名以当前目录中的文件名开头,而不是 ./

参见 Find.find

# File ext/pathname/lib/pathname.rb, line 571
def find(ignore_error: true) # :yield: pathname
  return to_enum(__method__, ignore_error: ignore_error) unless block_given?
  require 'find'
  if @path == '.'
    Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f.sub(%r{\A\./}, '')) }
  else
    Find.find(@path, ignore_error: ignore_error) {|f| yield self.class.new(f) }
  end
end
fnmatch(pattern, [flags]) → true 或 false 点击切换源代码

如果接收者与给定的模式匹配,则返回 true

参见 File.fnmatch

static VALUE
path_fnmatch(int argc, VALUE *argv, VALUE self)
{
    VALUE str = get_strpath(self);
    VALUE pattern, flags;
    if (rb_scan_args(argc, argv, "11", &pattern, &flags) == 1)
        return rb_funcall(rb_cFile, id_fnmatch, 2, pattern, str);
    else
        return rb_funcall(rb_cFile, id_fnmatch, 3, pattern, str, flags);
}
也称为:fnmatch?
fnmatch?(pattern, [flags]) → true 或 false

如果接收者与给定的模式匹配,则返回 true

参见 File.fnmatch

别名:fnmatch
freeze → obj 点击切换源代码

冻结此 Pathname 对象。

参见 Object.freeze

static VALUE
path_freeze(VALUE self)
{
    rb_call_super(0, 0);
    rb_str_freeze(get_strpath(self));
    return self;
}
ftype → string 点击切换源代码

返回文件的“类型”(“文件”、“目录”等)。

参见 File.ftype

static VALUE
path_ftype(VALUE self)
{
    return rb_funcall(rb_cFile, id_ftype, 1, get_strpath(self));
}
glob(p1, p2 = v2) 点击切换源代码

返回或生成 Pathname 对象。

Pathname("ruby-2.4.2").glob("R*.md")
#=> [#<Pathname:ruby-2.4.2/README.md>, #<Pathname:ruby-2.4.2/README.ja.md>]

参见 Dir.glob。此方法使用 Dir.globbase 关键字参数。

static VALUE
path_glob(int argc, VALUE *argv, VALUE self)
{
    VALUE args[3];
    int n;

    n = rb_scan_args(argc, argv, "11", &args[0], &args[1]);
    if (n == 1)
      args[1] = INT2FIX(0);

    args[2] = rb_hash_new();
    rb_hash_aset(args[2], ID2SYM(id_base), get_strpath(self));

    n = 3;

    if (rb_block_given_p()) {
        return rb_block_call_kw(rb_cDir, id_glob, n, args, glob_i, self, RB_PASS_KEYWORDS);
    }
    else {
        VALUE ary;
        long i;
        ary = rb_funcallv_kw(rb_cDir, id_glob, n, args, RB_PASS_KEYWORDS);
        ary = rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
        for (i = 0; i < RARRAY_LEN(ary); i++) {
            VALUE elt = RARRAY_AREF(ary, i);
            elt = rb_funcall(self, '+', 1, elt);
            rb_ary_store(ary, i, elt);
        }
        return ary;
    }
}
grpowned?() 点击切换源代码

参见 FileTest.grpowned?

static VALUE
path_grpowned_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_grpowned_p, 1, get_strpath(self));
}
join(*args) 点击切换源代码

将给定的路径名连接到 self 上,以创建一个新的 Pathname 对象。这实际上与使用 Pathname#+ 依次追加 self 和所有参数相同。

path0 = Pathname.new("/usr")                # Pathname:/usr
path0 = path0.join("bin/ruby")              # Pathname:/usr/bin/ruby
    # is the same as
path1 = Pathname.new("/usr") + "bin/ruby"   # Pathname:/usr/bin/ruby
path0 == path1
    #=> true
# File ext/pathname/lib/pathname.rb, line 416
def join(*args)
  return self if args.empty?
  result = args.pop
  result = Pathname.new(result) unless Pathname === result
  return result if result.absolute?
  args.reverse_each {|arg|
    arg = Pathname.new(arg) unless Pathname === arg
    result = arg + result
    return result if result.absolute?
  }
  self + result
end
lchmod(mode_int) → integer 点击切换源代码

Pathname.chmod 相同,但不跟随符号链接。

参见 File.lchmod

static VALUE
path_lchmod(VALUE self, VALUE mode)
{
    return rb_funcall(rb_cFile, id_lchmod, 2, mode, get_strpath(self));
}
lchown(owner_int, group_int) → integer 点击切换源代码

Pathname.chown 相同,但不跟随符号链接。

参见 File.lchown

static VALUE
path_lchown(VALUE self, VALUE owner, VALUE group)
{
    return rb_funcall(rb_cFile, id_lchown, 3, owner, group, get_strpath(self));
}
lstat() 点击切换源代码

参见 File.lstat

static VALUE
path_lstat(VALUE self)
{
    return rb_funcall(rb_cFile, id_lstat, 1, get_strpath(self));
}
lutime(p1, p2) 点击切换源代码

更新文件的访问和修改时间。

Pathname#utime 相同,但不跟随符号链接。

参见 File.lutime

static VALUE
path_lutime(VALUE self, VALUE atime, VALUE mtime)
{
    return rb_funcall(rb_cFile, id_lutime, 3, atime, mtime, get_strpath(self));
}
mkdir(p1 = v1) 点击切换源代码

创建引用的目录。

参见 Dir.mkdir

static VALUE
path_mkdir(int argc, VALUE *argv, VALUE self)
{
    VALUE str = get_strpath(self);
    VALUE vmode;
    if (rb_scan_args(argc, argv, "01", &vmode) == 0)
        return rb_funcall(rb_cDir, id_mkdir, 1, str);
    else
        return rb_funcall(rb_cDir, id_mkdir, 2, str, vmode);
}
mkpath(mode: nil) 点击切换源代码

创建完整路径,包括任何尚不存在的中间目录。

参见 FileUtils.mkpathFileUtils.mkdir_p

# File ext/pathname/lib/pathname.rb, line 590
def mkpath(mode: nil)
  FileUtils.mkpath(@path, mode: mode)
  nil
end
mountpoint?() 点击切换源代码

如果 self 指向挂载点,则返回 true

# File ext/pathname/lib/pathname.rb, line 201
def mountpoint?
  begin
    stat1 = self.lstat
    stat2 = self.parent.lstat
    stat1.dev != stat2.dev || stat1.ino == stat2.ino
  rescue Errno::ENOENT
    false
  end
end
mtime → time 点击切换源代码

返回文件的最后修改时间。

参见 File.mtime

static VALUE
path_mtime(VALUE self)
{
    return rb_funcall(rb_cFile, id_mtime, 1, get_strpath(self));
}
open() 点击切换源代码
open(mode="r" [, opt]) → file
open([mode [, perm]] [, opt]) → file
open(mode="r" [, opt]) {|file| block } → obj
open([mode [, perm]] [, opt]) {|file| block } → obj

打开文件以供读取或写入。

参见 File.open.

static VALUE
path_open(int argc, VALUE *argv, VALUE self)
{
    VALUE args[4];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
    if (rb_block_given_p()) {
        return rb_block_call_kw(rb_cFile, id_open, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
    }
    else {
        return rb_funcallv_kw(rb_cFile, id_open, 1+n, args, RB_PASS_CALLED_KEYWORDS);
    }
}
opendir() 点击切换源代码

打开引用的目录。

参见 Dir.open.

static VALUE
path_opendir(VALUE self)
{
    VALUE args[1];

    args[0] = get_strpath(self);
    return rb_block_call(rb_cDir, id_open, 1, args, 0, 0);
}
owned?() 点击切换源代码

参见 FileTest.owned?.

static VALUE
path_owned_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_owned_p, 1, get_strpath(self));
}
parent() 点击切换源代码

返回父目录。

这与 self + '..' 相同。

# File ext/pathname/lib/pathname.rb, line 196
def parent
  self + '..'
end
pipe?() 点击切换源代码

参见 FileTest.pipe?.

static VALUE
path_pipe_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_pipe_p, 1, get_strpath(self));
}
read([length [, offset]]) → string 点击切换源代码
read([length [, offset]], open_args) → string

返回文件中的所有数据,如果指定,则返回前 N 个字节。

参见 File.read.

static VALUE
path_read(int argc, VALUE *argv, VALUE self)
{
    VALUE args[4];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
    return rb_funcallv_kw(rb_cFile, id_read, 1+n, args, RB_PASS_CALLED_KEYWORDS);
}
readable?() 点击切换源代码

参见 FileTest.readable?.

static VALUE
path_readable_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_readable_p, 1, get_strpath(self));
}
readable_real?() 点击切换源代码

参见 FileTest.readable_real?.

static VALUE
path_readable_real_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_readable_real_p, 1, get_strpath(self));
}
readlines(sep=$/ [, open_args]) → array 点击切换源代码
readlines(limit [, open_args]) → array
readlines(sep, limit [, open_args]) → array

返回文件中的所有行。

参见 File.readlines.

static VALUE
path_readlines(int argc, VALUE *argv, VALUE self)
{
    VALUE args[4];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
    return rb_funcallv_kw(rb_cFile, id_readlines, 1+n, args, RB_PASS_CALLED_KEYWORDS);
}
realdirpath(p1 = v1) 点击切换源代码

返回 self 在实际文件系统中的真实(绝对)路径。

不包含符号链接或无用的点,...

实际路径名的最后一个组件可能不存在。

static VALUE
path_realdirpath(int argc, VALUE *argv, VALUE self)
{
    VALUE basedir, str;
    rb_scan_args(argc, argv, "01", &basedir);
    str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir);
    return rb_class_new_instance(1, &str, rb_obj_class(self));
}
realpath(p1 = v1) 点击切换源代码

返回self在实际文件系统中的真实(绝对)路径名。

不包含符号链接或无用的点,...

调用此方法时,路径名的所有组件都必须存在。

static VALUE
path_realpath(int argc, VALUE *argv, VALUE self)
{
    VALUE basedir, str;
    rb_scan_args(argc, argv, "01", &basedir);
    str = rb_funcall(rb_cFile, id_realpath, 2, get_strpath(self), basedir);
    return rb_class_new_instance(1, &str, rb_obj_class(self));
}
relative?() 点击切换源代码

Pathname#absolute? 的反面

如果路径名以斜杠开头,则返回false

p = Pathname.new('/im/sure')
p.relative?
    #=> false

p = Pathname.new('not/so/sure')
p.relative?
    #=> true
# File ext/pathname/lib/pathname.rb, line 248
def relative?
  !absolute?
end
relative_path_from(base_directory) 点击切换源代码

返回从给定的base_directory到接收者的相对路径。

如果self是绝对的,则base_directory也必须是绝对的。

如果self是相对的,则base_directory也必须是相对的。

此方法不访问文件系统。它假设没有符号链接。

当找不到相对路径时,会引发ArgumentError

请注意,此方法不处理使用中的文件系统的大小写敏感性与操作系统默认值不同的情况。

# File ext/pathname/lib/pathname.rb, line 517
def relative_path_from(base_directory)
  base_directory = Pathname.new(base_directory) unless base_directory.is_a? Pathname
  dest_directory = self.cleanpath.to_s
  base_directory = base_directory.cleanpath.to_s
  dest_prefix = dest_directory
  dest_names = []
  while r = chop_basename(dest_prefix)
    dest_prefix, basename = r
    dest_names.unshift basename if basename != '.'
  end
  base_prefix = base_directory
  base_names = []
  while r = chop_basename(base_prefix)
    base_prefix, basename = r
    base_names.unshift basename if basename != '.'
  end
  unless SAME_PATHS[dest_prefix, base_prefix]
    raise ArgumentError, "different prefix: #{dest_prefix.inspect} and #{base_directory.inspect}"
  end
  while !dest_names.empty? &&
        !base_names.empty? &&
        SAME_PATHS[dest_names.first, base_names.first]
    dest_names.shift
    base_names.shift
  end
  if base_names.include? '..'
    raise ArgumentError, "base_directory has ..: #{base_directory.inspect}"
  end
  base_names.fill('..')
  relpath_names = base_names + dest_names
  if relpath_names.empty?
    Pathname.new('.')
  else
    Pathname.new(File.join(*relpath_names))
  end
end
rename(p1) 点击切换源代码

重命名文件。

参见File.rename

static VALUE
path_rename(VALUE self, VALUE to)
{
    return rb_funcall(rb_cFile, id_rename, 2, get_strpath(self), to);
}
rmdir() 点击切换源代码

删除引用的目录。

参见Dir.rmdir

static VALUE
path_rmdir(VALUE self)
{
    return rb_funcall(rb_cDir, id_rmdir, 1, get_strpath(self));
}
rmtree(noop: nil, verbose: nil, secure: nil) 点击切换源代码

递归删除目录,包括其下的所有目录。

参见FileUtils.rm_rf

# File ext/pathname/lib/pathname.rb, line 598
def rmtree(noop: nil, verbose: nil, secure: nil)
  # The name "rmtree" is borrowed from File::Path of Perl.
  # File::Path provides "mkpath" and "rmtree".
  require 'fileutils'
  FileUtils.rm_rf(@path, noop: noop, verbose: verbose, secure: secure)
  nil
end
root?() 点击切换源代码

根目录的谓词方法。如果路径名由连续的斜杠组成,则返回true

它不访问文件系统。因此,它可能对指向根目录的一些路径名返回false,例如/usr/..

# File ext/pathname/lib/pathname.rb, line 218
def root?
  chop_basename(@path) == nil && /#{SEPARATOR_PAT}/o.match?(@path)
end
setgid?() 点击切换源代码

参见FileTest.setgid?

static VALUE
path_setgid_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_setgid_p, 1, get_strpath(self));
}
setuid?() 点击切换源代码

参见 FileTest.setuid?

static VALUE
path_setuid_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_setuid_p, 1, get_strpath(self));
}
size() 点击切换源代码

参见 FileTest.size

static VALUE
path_size(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_size, 1, get_strpath(self));
}
size?() 点击切换源代码

参见 FileTest.size?

static VALUE
path_size_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_size_p, 1, get_strpath(self));
}
socket?() 点击切换源代码

参见 FileTest.socket?

static VALUE
path_socket_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_socket_p, 1, get_strpath(self));
}
split() 点击切换源代码

返回一个 Array,包含 dirnamebasename

参见 File.split

static VALUE
path_split(VALUE self)
{
    VALUE str = get_strpath(self);
    VALUE ary, dirname, basename;
    ary = rb_funcall(rb_cFile, id_split, 1, str);
    Check_Type(ary, T_ARRAY);
    dirname = rb_ary_entry(ary, 0);
    basename = rb_ary_entry(ary, 1);
    dirname = rb_class_new_instance(1, &dirname, rb_obj_class(self));
    basename = rb_class_new_instance(1, &basename, rb_obj_class(self));
    return rb_ary_new3(2, dirname, basename);
}
stat() 点击切换源代码

返回一个 File::Stat 对象。

参见 File.stat

static VALUE
path_stat(VALUE self)
{
    return rb_funcall(rb_cFile, id_stat, 1, get_strpath(self));
}
sticky?() 点击切换源代码

参见 FileTest.sticky?

static VALUE
path_sticky_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_sticky_p, 1, get_strpath(self));
}
sub(*args) 点击切换源代码

返回一个使用 String#sub 替换后的路径名。

path1 = Pathname.new('/usr/bin/perl')
path1.sub('perl', 'ruby')
    #=> #<Pathname:/usr/bin/ruby>
static VALUE
path_sub(int argc, VALUE *argv, VALUE self)
{
    VALUE str = get_strpath(self);

    if (rb_block_given_p()) {
        str = rb_block_call(str, id_sub, argc, argv, 0, 0);
    }
    else {
        str = rb_funcallv(str, id_sub, argc, argv);
    }
    return rb_class_new_instance(1, &str, rb_obj_class(self));
}
sub_ext(p1) 点击切换源代码

返回一个路径名,其基名后缀为 repl

如果 self 没有扩展名部分,则附加 repl

Pathname.new('/usr/bin/shutdown').sub_ext('.rb')
    #=> #<Pathname:/usr/bin/shutdown.rb>
static VALUE
path_sub_ext(VALUE self, VALUE repl)
{
    VALUE str = get_strpath(self);
    VALUE str2;
    long extlen;
    const char *ext;
    const char *p;

    StringValue(repl);
    p = RSTRING_PTR(str);
    extlen = RSTRING_LEN(str);
    ext = ruby_enc_find_extname(p, &extlen, rb_enc_get(str));
    if (ext == NULL) {
        ext = p + RSTRING_LEN(str);
    }
    else if (extlen <= 1) {
        ext += extlen;
    }
    str2 = rb_str_subseq(str, 0, ext-p);
    rb_str_append(str2, repl);
    return rb_class_new_instance(1, &str2, rb_obj_class(self));
}
sysopen([mode, [perm]]) → fixnum 点击切换源代码

参见 IO.sysopen

static VALUE
path_sysopen(int argc, VALUE *argv, VALUE self)
{
    VALUE args[3];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "02", &args[1], &args[2]);
    return rb_funcallv(rb_cIO, id_sysopen, 1+n, args);
}
to_path → string

返回路径作为 String

to_path 的实现使得 Pathname 对象可用于 File.open 等。

别名:to_s
to_s → string 点击切换源代码

返回路径作为 String

to_path 的实现使得 Pathname 对象可用于 File.open 等。

static VALUE
path_to_s(VALUE self)
{
    return rb_obj_dup(get_strpath(self));
}
别名:to_path
truncate(p1) 点击切换源代码

将文件截断为 length 字节。

参见 File.truncate

static VALUE
path_truncate(VALUE self, VALUE length)
{
    return rb_funcall(rb_cFile, id_truncate, 2, get_strpath(self), length);
}
utime(p1, p2) 点击切换源代码

更新文件的访问和修改时间。

参见 File.utime.

static VALUE
path_utime(VALUE self, VALUE atime, VALUE mtime)
{
    return rb_funcall(rb_cFile, id_utime, 3, atime, mtime, get_strpath(self));
}
world_readable?() 点击切换源代码

参见 FileTest.world_readable?.

static VALUE
path_world_readable_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_world_readable_p, 1, get_strpath(self));
}
world_writable?() 点击切换源代码

参见 FileTest.world_writable?.

static VALUE
path_world_writable_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_world_writable_p, 1, get_strpath(self));
}
writable?() 点击切换源代码

参见 FileTest.writable?.

static VALUE
path_writable_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_writable_p, 1, get_strpath(self));
}
writable_real?() 点击切换源代码

参见 FileTest.writable_real?.

static VALUE
path_writable_real_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_writable_real_p, 1, get_strpath(self));
}
write(string, [offset] ) → fixnum 点击切换源代码
write(string, [offset], open_args ) → fixnum

contents写入文件。

参见 File.write.

static VALUE
path_write(int argc, VALUE *argv, VALUE self)
{
    VALUE args[4];
    int n;

    args[0] = get_strpath(self);
    n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
    return rb_funcallv_kw(rb_cFile, id_write, 1+n, args, RB_PASS_CALLED_KEYWORDS);
}
zero?() 点击切换源代码

参见 FileTest.zero?.

static VALUE
path_zero_p(VALUE self)
{
    return rb_funcall(rb_mFileTest, id_zero_p, 1, get_strpath(self));
}