类 Dir

Dir 类对象表示底层文件系统中的目录。

它主要包含

  • 一个字符串 path,在创建对象时给出,它指定底层文件系统中的目录;方法 path 返回路径。

  • 一个字符串 条目名称 集合,每个名称都是底层文件系统中目录或文件的名称;条目名称可以以 类似数组的方式类似流的方式 检索。

关于示例

此页面上的一些示例使用这个简单的文件树

example/
├── config.h
├── lib/
│   ├── song/
│   │   └── karaoke.rb
│   └── song.rb
└── main.rb

其他示例使用 Ruby 项目本身 的文件树。

Dir 作为数组

Dir 对象在某些方面类似数组

Dir 作为流

Dir 对象在某些方面类似流。

流最初处于打开状态以供读取,但可以手动关闭(使用方法 close),如果由 Dir.open 调用带有块的方式创建,则在块退出时将关闭。关闭的流不能进一步操作,也不能重新打开。

流有一个位置,它是目录中条目的索引

  • 初始位置为零(在第一个条目之前)。

  • 方法 tell(别名为 pos)返回位置。

  • 方法 pos= 设置位置(但忽略流之外的值),并返回位置。

  • 方法 seek 类似于 pos=,但返回 self(便于链接)。

  • 方法 read,如果不在流末尾,则读取下一个条目并增加位置;如果在流末尾,则不增加位置。

  • 方法 rewind 将位置设置为零。

示例(使用 简单文件树

dir = Dir.new('example') # => #<Dir:example>
dir.pos                  # => 0

dir.read # => "."
dir.read # => ".."
dir.read # => "config.h"
dir.read # => "lib"
dir.read # => "main.rb"
dir.pos  # => 5
dir.read # => nil
dir.pos  # => 5

dir.rewind # => #<Dir:example>
dir.pos    # => 0

dir.pos = 3 # => 3
dir.pos     # => 3

dir.seek(4) # => #<Dir:example>
dir.pos     # => 4

dir.close # => nil
dir.read  # Raises IOError.

这里有什么

首先,其他地方有什么。类 Dir

这里,类 Dir 提供了对以下内容有用的方法

读取

  • close: 关闭 self 的目录流。

  • pos=: 设置 self 的目录流中的位置。

  • read: 读取并返回 self 的目录流中的下一个条目。

  • rewind: 将 self 的目录流中的位置设置为第一个条目。

  • seek: 将 self 的目录流中的位置设置为给定偏移量的条目。

设置

  • ::chdir: 将当前进程的工作目录更改为给定目录。

  • ::chroot: 将当前进程的文件系统根目录更改为给定目录。

查询

  • ::[]: 与 ::glob 相同,但不能传递标志。

  • ::children: 返回给定目录中子项(文件和目录)的名称数组,但不包括 ...

  • ::empty?: 返回给定路径是否为空目录。

  • ::entries: 返回给定目录中子项(文件和目录)的名称数组,包括 ...

  • ::exist?: 返回给定路径是否为目录。

  • ::getwd (别名为 pwd): 返回当前工作目录的路径。

  • ::glob: 返回与给定模式和标志匹配的文件路径数组。

  • ::home: 返回给定用户或当前用户的家目录路径。

  • children: 返回 self 的子项(文件和目录)的名称数组,但不包括 ...

  • fileno: 返回 self 的整数文件描述符。

  • path (别名为 to_path): 返回用于创建 self 的路径。

  • tell (别名为 pos): 返回 self 在目录流中的整数位置。

迭代

  • ::each_child: 使用给定目录中的每个条目调用给定块,但不包括 ...

  • ::foreach: 使用给定目录中的每个条目调用给定块,包括 ...

  • each: 使用 self 中的每个条目调用给定块,包括 ...

  • each_child: 使用 self 中的每个条目调用给定块,但不包括 ...

其他

  • ::mkdir: 在给定路径上创建目录,可以选择权限。

  • ::new: 返回给定路径的新 Dir,可以选择编码。

  • ::open: 与 ::new 相同,但如果给定代码块,则将 Dir 产生到代码块,在代码块退出时关闭它。

  • ::unlink (别名为 ::delete::rmdir): 删除给定的目录。

  • inspect: 返回 self 的字符串描述。

公共类方法

Dir[*patterns, base: nil, sort: true] → array click to toggle source

调用 Dir.glob,参数为 patterns 以及关键字参数 basesort 的值;返回选定条目名称的数组。

# File ruby_3_3_0/dir.rb, line 222
def self.[](*args, base: nil, sort: true)
  Primitive.dir_s_aref(args, base, sort)
end
chdir(new_dirpath) → 0 click to toggle source
chdir → 0
chdir(new_dirpath) {|new_dirpath| ... } → object
chdir {|cur_dirpath| ... } → object

更改当前工作目录。

带参数 new_dirpath 且没有代码块,更改到给定的 dirpath

Dir.pwd         # => "/example"
Dir.chdir('..') # => 0
Dir.pwd         # => "/"

没有参数且没有代码块

  • 如果定义了,则更改到环境变量 HOME 的值。

  • 否则,如果定义了,则更改到环境变量 LOGDIR 的值。

  • 否则不进行更改。

带参数 new_dirpath 且带代码块,临时更改工作目录

  • 用参数调用代码块。

  • 更改到给定的目录。

  • 执行代码块(产生新路径)。

  • 恢复以前的工作目录。

  • 返回代码块的返回值。

示例

Dir.chdir('/var/spool/mail')
Dir.pwd   # => "/var/spool/mail"
Dir.chdir('/tmp') do
  Dir.pwd # => "/tmp"
end
Dir.pwd   # => "/var/spool/mail"

没有参数且带代码块,用当前工作目录(字符串)调用代码块,并返回代码块的返回值。

对 Dir.chdir 的调用可以嵌套代码块。

Dir.chdir('/var/spool/mail')
Dir.pwd     # => "/var/spool/mail"
Dir.chdir('/tmp') do
  Dir.pwd   # => "/tmp"
  Dir.chdir('/usr') do
    Dir.pwd # => "/usr"
  end
  Dir.pwd   # => "/tmp"
end
Dir.pwd     # => "/var/spool/mail"

在多线程程序中,如果一个线程试图打开一个 chdir 代码块,而另一个线程已经打开了一个代码块,或者在传递给 chdir 的代码块内(即使在同一个线程中)调用了没有代码块的 chdir,则会引发错误。

如果目标目录不存在,则引发异常。

static VALUE
dir_s_chdir(int argc, VALUE *argv, VALUE obj)
{
    VALUE path = Qnil;

    if (rb_check_arity(argc, 0, 1) == 1) {
        path = rb_str_encode_ospath(rb_get_path(argv[0]));
    }
    else {
        const char *dist = getenv("HOME");
        if (!dist) {
            dist = getenv("LOGDIR");
            if (!dist) rb_raise(rb_eArgError, "HOME/LOGDIR not set");
        }
        path = rb_str_new2(dist);
    }

    return chdir_path(path, true);
}
children(dirpath) → array click to toggle source
children(dirpath, encoding: 'UTF-8') → array

返回 dirpath 目录中除 '.''..' 之外的所有条目名称的数组;将给定的编码设置到每个返回的条目名称上

Dir.children('/example') # => ["config.h", "lib", "main.rb"]
Dir.children('/example').first.encoding
# => #<Encoding:UTF-8>
Dir.children('/example', encoding: 'US-ASCII').first.encoding
# => #<Encoding:US-ASCII>

参见 字符串编码.

如果目录不存在,则引发异常。

static VALUE
dir_s_children(int argc, VALUE *argv, VALUE io)
{
    VALUE dir;

    dir = dir_open_dir(argc, argv);
    return rb_ensure(dir_collect_children, dir, dir_close, dir);
}
chroot(dirpath) → 0 点击切换源代码

将调用进程的根目录更改为 dirpath 中指定的目录。新根目录用于以 '/' 开头的路径名。根目录由调用进程的所有子进程继承。

只有特权进程才能调用 chroot

参见 Linux chroot.

static VALUE
dir_s_chroot(VALUE dir, VALUE path)
{
    path = check_dirname(path);
    if (chroot(RSTRING_PTR(path)) == -1)
        rb_sys_fail_path(path);

    return INT2FIX(0);
}
rmdir(dirpath) → 0 点击切换源代码

从底层文件系统中删除 dirpath 处的目录

Dir.rmdir('foo') # => 0

如果目录不为空,则引发异常。

static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
{
    const char *p;
    int r;

    dir = check_dirname(dir);
    p = RSTRING_PTR(dir);
    r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_rmdir, (void *)p, RUBY_UBF_IO, 0);
    if (r < 0)
        rb_sys_fail_path(dir);

    return INT2FIX(0);
}
each_child(dirpath) {|entry_name| ... } → nil 点击切换源代码
each_child(dirpath, encoding: 'UTF-8') {|entry_name| ... } → nil

Dir.foreach 相似,但不会包含条目 '.''..'

static VALUE
dir_s_each_child(int argc, VALUE *argv, VALUE io)
{
    VALUE dir;

    RETURN_ENUMERATOR(io, argc, argv);
    dir = dir_open_dir(argc, argv);
    rb_ensure(dir_each_child, dir, dir_close, dir);
    return Qnil;
}
empty?(dirpath) → true 或 false 点击切换源代码

返回 dirpath 是否指定一个空目录

dirpath = '/tmp/foo'
Dir.mkdir(dirpath)
Dir.empty?(dirpath)            # => true
Dir.empty?('/example')         # => false
Dir.empty?('/example/main.rb') # => false

如果 dirpath 未指定底层文件系统中的目录或文件,则引发异常。

static VALUE
rb_dir_s_empty_p(VALUE obj, VALUE dirname)
{
    VALUE result, orig;
    const char *path;
    enum {false_on_notdir = 1};

    FilePathValue(dirname);
    orig = rb_str_dup_frozen(dirname);
    dirname = rb_str_encode_ospath(dirname);
    dirname = rb_str_dup_frozen(dirname);
    path = RSTRING_PTR(dirname);

#if defined HAVE_GETATTRLIST && defined ATTR_DIR_ENTRYCOUNT
    {
        u_int32_t attrbuf[SIZEUP32(fsobj_tag_t)];
        struct attrlist al = {ATTR_BIT_MAP_COUNT, 0, ATTR_CMN_OBJTAG,};
        if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) != 0)
            rb_sys_fail_path(orig);
        if (*(const fsobj_tag_t *)(attrbuf+1) == VT_HFS) {
            al.commonattr = 0;
            al.dirattr = ATTR_DIR_ENTRYCOUNT;
            if (getattrlist(path, &al, attrbuf, sizeof(attrbuf), 0) == 0) {
                if (attrbuf[0] >= 2 * sizeof(u_int32_t))
                    return RBOOL(attrbuf[1] == 0);
                if (false_on_notdir) return Qfalse;
            }
            rb_sys_fail_path(orig);
        }
    }
#endif

    result = (VALUE)rb_thread_call_without_gvl(nogvl_dir_empty_p, (void *)path,
                                            RUBY_UBF_IO, 0);
    if (FIXNUM_P(result)) {
        rb_syserr_fail_path((int)FIX2LONG(result), orig);
    }
    return result;
}
entries(dirname, encoding: 'UTF-8') → array 点击切换源代码

返回 dirpath 目录中所有条目名称的数组;将给定的编码设置到每个返回的条目名称上

Dir.entries('/example') # => ["config.h", "lib", "main.rb", "..", "."]
Dir.entries('/example').first.encoding
# => #<Encoding:UTF-8>
Dir.entries('/example', encoding: 'US-ASCII').first.encoding
# => #<Encoding:US-ASCII>

参见 字符串编码.

如果目录不存在,则引发异常。

static VALUE
dir_entries(int argc, VALUE *argv, VALUE io)
{
    VALUE dir;

    dir = dir_open_dir(argc, argv);
    return rb_ensure(dir_collect, dir, dir_close, dir);
}
exist?(dirpath) → true 或 false 点击切换源代码

返回 dirpath 是否是底层文件系统中的目录

Dir.exist?('/example')         # => true
Dir.exist?('/nosuch')          # => false
Dir.exist?('/example/main.rb') # => false

File.directory? 相同。

VALUE
rb_file_directory_p(void)
{
}
fchdir(fd) → 0 点击切换源代码
fchdir(fd) { ... } → object

将当前工作目录更改为由整数文件描述符 fd 指定的目录。

当通过 UNIX 套接字或传递给子进程传递文件描述符时,使用 fchdir 而不是 chdir 可以避免 检查时到使用时漏洞

没有块时,更改为 fd 给出的目录

Dir.chdir('/var/spool/mail')
Dir.pwd # => "/var/spool/mail"
dir  = Dir.new('/usr')
fd = dir.fileno
Dir.fchdir(fd)
Dir.pwd # => "/usr"

有块时,临时更改工作目录

  • 用参数调用代码块。

  • 更改到给定的目录。

  • 执行块(不产生参数)。

  • 恢复以前的工作目录。

  • 返回代码块的返回值。

示例

Dir.chdir('/var/spool/mail')
Dir.pwd # => "/var/spool/mail"
dir  = Dir.new('/tmp')
fd = dir.fileno
Dir.fchdir(fd) do
  Dir.pwd # => "/tmp"
end
Dir.pwd # => "/var/spool/mail"

此方法使用 POSIX 2008 定义的 fchdir() 函数;该方法在非 POSIX 平台上未实现(引发 NotImplementedError)。

如果文件描述符无效,则引发异常。

在多线程程序中,如果一个线程试图打开一个 chdir 代码块,而另一个线程已经打开了一个代码块,或者在传递给 chdir 的代码块内(即使在同一个线程中)调用了没有代码块的 chdir,则会引发错误。

static VALUE
dir_s_fchdir(VALUE klass, VALUE fd_value)
{
    int fd = RB_NUM2INT(fd_value);

    if (chdir_blocking > 0) {
        if (rb_thread_current() != chdir_thread)
            rb_raise(rb_eRuntimeError, "conflicting chdir during another chdir block");
        if (!rb_block_given_p())
            rb_warn("conflicting chdir during another chdir block");
    }

    if (rb_block_given_p()) {
        struct fchdir_data args;
        args.old_dir = dir_s_alloc(klass);
        dir_initialize(NULL, args.old_dir, rb_fstring_cstr("."), Qnil);
        args.fd = fd;
        args.done = FALSE;
        return rb_ensure(fchdir_yield, (VALUE)&args, fchdir_restore, (VALUE)&args);
    }
    else {
        int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_fchdir, &fd,
                                                       RUBY_UBF_IO, 0);
        if (r < 0)
            rb_sys_fail("fchdir");
    }

    return INT2FIX(0);
}
for_fd(fd) → dir 点击切换源代码

返回一个新的 Dir 对象,表示由给定整数目录文件描述符 fd 指定的目录。

d0 = Dir.new('..')
d1 = Dir.for_fd(d0.fileno)

注意,返回的 d1 没有关联的路径。

d0.path # => '..'
d1.path # => nil

此方法使用 POSIX 2008 定义的 fdopendir() 函数;该方法在非 POSIX 平台上未实现(引发 NotImplementedError)。

static VALUE
dir_s_for_fd(VALUE klass, VALUE fd)
{
    struct dir_data *dp;
    VALUE dir = TypedData_Make_Struct(klass, struct dir_data, &dir_data_type, dp);

    if (!(dp->dir = fdopendir(NUM2INT(fd)))) {
        rb_sys_fail("fdopendir");
        UNREACHABLE_RETURN(Qnil);
    }

    RB_OBJ_WRITE(dir, &dp->path, Qnil);
    return dir;
}
foreach(dirpath, encoding: 'UTF-8') {|entry_name| ... } → nil 点击切换源代码

使用 dirpath 中目录中的每个条目名称调用块;将给定的编码设置到每个传递的 entry_name 上。

Dir.foreach('/example') {|entry_name| p entry_name }

输出

"config.h"
"lib"
"main.rb"
".."
"."

编码

Dir.foreach('/example') {|entry_name| p entry_name.encoding; break }
Dir.foreach('/example', encoding: 'US-ASCII') {|entry_name| p entry_name.encoding; break }

输出

#<Encoding:UTF-8>
#<Encoding:US-ASCII>

参见 字符串编码.

如果没有给出块,则返回一个枚举器。

static VALUE
dir_foreach(int argc, VALUE *argv, VALUE io)
{
    VALUE dir;

    RETURN_ENUMERATOR(io, argc, argv);
    dir = dir_open_dir(argc, argv);
    rb_ensure(dir_each, dir, dir_close, dir);
    return Qnil;
}
pwd → string 点击切换源代码

返回当前工作目录的路径。

Dir.chdir("/tmp") # => 0
Dir.pwd           # => "/tmp"
static VALUE
dir_s_getwd(VALUE dir)
{
    return rb_dir_getwd();
}
glob(*patterns, flags: 0, base: nil, sort: true) → array 点击切换源代码
glob(*patterns, flags: 0, base: nil, sort: true) {|entry_name| ... } → nil

形成一个 entry_names 数组,其中包含由参数选择的条目名称。

参数 patterns 是一个字符串模式或一个字符串模式数组;注意,这些不是正则表达式;见下文。

以下示例的说明

  • '*' 是匹配除以 '.' 开头的条目名称之外的任何条目名称的模式。

  • 我们使用方法 Array#take 来缩短返回的数组,否则这些数组会非常大。

如果没有块,则返回数组 entry_names;示例(使用 简单文件树

Dir.glob('*') # => ["config.h", "lib", "main.rb"]

如果有块,则使用每个 entry_names 调用块,并返回 nil

Dir.glob('*') {|entry_name| puts entry_name } # => nil

输出

config.h
lib
main.rb

如果给出了可选的关键字参数 flags,则该值会修改匹配;见下文。

如果提供了可选的关键字参数 base,它的值将指定基本目录。每个模式字符串指定相对于基本目录的条目;默认值为 '.'。基本目录不会附加到结果中的条目名称。

Dir.glob(pattern, base: 'lib').take(5)
# => ["abbrev.gemspec", "abbrev.rb", "base64.gemspec", "base64.rb", "benchmark.gemspec"]
Dir.glob(pattern, base: 'lib/irb').take(5)
# => ["cmd", "color.rb", "color_printer.rb", "completion.rb", "context.rb"]

如果提供了可选的关键字 sort,它的值将指定是否对数组进行排序;默认值为 true。使用该关键字传递值 false 将禁用排序(尽管底层文件系统可能已经对数组进行了排序)。

模式

每个模式字符串根据某些元字符进行扩展;以下示例使用 Ruby 文件树

  • '*':匹配条目名称中的任何子字符串,类似于正则表达式 /.*/mx 的含义;可能受模式字符串中的其他值限制

    • '*' 匹配所有条目名称

      Dir.glob('*').take(3)  # => ["BSDL", "CONTRIBUTING.md", "COPYING"]
      
    • 'c*' 匹配以 'c' 开头的条目名称

      Dir.glob('c*').take(3) # => ["CONTRIBUTING.md", "COPYING", "COPYING.ja"]
      
    • '*c' 匹配以 'c' 结尾的条目名称

      Dir.glob('*c').take(3) # => ["addr2line.c", "array.c", "ast.c"]
      
    • '*c*' 匹配包含 'c' 的条目名称,即使在开头或结尾

      Dir.glob('*c*').take(3) # => ["CONTRIBUTING.md", "COPYING", "COPYING.ja"]
      

    不匹配类 Unix 隐藏条目名称(“点文件”)。要将这些包含在匹配的条目名称中,请使用标志 IO::FNM_DOTMATCH 或类似 '{*,.*}' 的内容。

  • '**':如果后面跟着斜杠字符 '/',则递归匹配条目名称

    Dir.glob('**/').take(3) # => ["basictest/", "benchmark/", "benchmark/gc/"]
    

    如果字符串模式包含其他字符或后面没有斜杠字符,则等效于 '*'

  • '?' 匹配任何单个字符;类似于正则表达式 /./ 的含义

    Dir.glob('io.?') # => ["io.c"]
    
  • '[set]':匹配字符串 set 中的任何一个字符;行为类似于 正则表达式字符类,包括集合否定('[^a-z]'

    Dir.glob('*.[a-z][a-z]').take(3)
    # => ["CONTRIBUTING.md", "COPYING.ja", "KNOWNBUGS.rb"]
    
  • '{abc,xyz}':匹配字符串 abc 或字符串 xyz;行为类似于 {正则表达式交替}[rdoc-ref:Regexp@Alternation]

    Dir.glob('{LEGAL,BSDL}') # => ["LEGAL", "BSDL"]
    

    可以给出两个以上的备选方案。

  • \:转义以下元字符。

    请注意,在 Windows 上,反斜杠字符不能在字符串模式中使用:Dir['c:\foo*'] 将不起作用,请改用 Dir['c:/foo*']

更多示例(使用 简单文件树)

# We're in the example directory.
File.basename(Dir.pwd) # => "example"
Dir.glob('config.?')              # => ["config.h"]
Dir.glob('*.[a-z][a-z]')          # => ["main.rb"]
Dir.glob('*.[^r]*')               # => ["config.h"]
Dir.glob('*.{rb,h}')              # => ["main.rb", "config.h"]
Dir.glob('*')                     # => ["config.h", "lib", "main.rb"]
Dir.glob('*', File::FNM_DOTMATCH) # => [".", "config.h", "lib", "main.rb"]
Dir.glob(["*.rb", "*.h"])         # => ["main.rb", "config.h"]

Dir.glob('**/*.rb')
=> ["lib/song/karaoke.rb", "lib/song.rb", "main.rb"]

Dir.glob('**/*.rb', base: 'lib')  #   => ["song/karaoke.rb", "song.rb"]

Dir.glob('**/lib')                # => ["lib"]

Dir.glob('**/lib/**/*.rb')        # => ["lib/song/karaoke.rb", "lib/song.rb"]

Dir.glob('**/lib/*.rb')           # => ["lib/song.rb"]

标志

如果提供了可选的关键字参数 flags(默认值为零,表示没有标志),则其值应为模块 File::Constants 中定义的一个或多个常量的按位或运算结果。

示例

flags = File::FNM_EXTGLOB | File::FNM_DOTMATCH

指定标志可以扩展、限制或以其他方式修改匹配。

此方法的标志(File::Constants 中的其他常量不适用)

  • File::FNM_DOTMATCH:指定以 '.' 开头的条目名称应被视为匹配对象

    Dir.glob('*').take(5)
    # => ["BSDL", "CONTRIBUTING.md", "COPYING", "COPYING.ja", "GPL"]
    Dir.glob('*', flags: File::FNM_DOTMATCH).take(5)
    # => [".", ".appveyor.yml", ".cirrus.yml", ".dir-locals.el", ".document"]
    
  • File::FNM_EXTGLOB:启用模式扩展 '{a,b}',它匹配模式 a 和模式 b;行为类似于 {regexp union}[rdoc-ref:Regexp.union](例如,'(?:a|b)'

    pattern = '{LEGAL,BSDL}'
    Dir.glob(pattern)      # => ["LEGAL", "BSDL"]
    
  • File::FNM_NOESCAPE:指定禁用反斜杠字符 '\' 的转义;该字符不是转义字符。

  • File::FNM_PATHNAME:指定元字符 '*''?' 不匹配目录分隔符。

  • File::FNM_SHORTNAME:指定模式如果存在,可以匹配短名称;仅限 Windows。

# File ruby_3_3_0/dir.rb, line 410
def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true)
  Primitive.dir_s_glob(pattern, flags, base, sort)
end
home(user_name = nil) → dirpath click to toggle source

如果 user_name 不为 nil,则返回 user_name 指定的用户的主目录路径,否则返回当前登录用户的路径

Dir.home         # => "/home/me"
Dir.home('root') # => "/root"

如果 user_name 不是用户名,则引发 ArgumentError

static VALUE
dir_s_home(int argc, VALUE *argv, VALUE obj)
{
    VALUE user;
    const char *u = 0;

    rb_check_arity(argc, 0, 1);
    user = (argc > 0) ? argv[0] : Qnil;
    if (!NIL_P(user)) {
        SafeStringValue(user);
        rb_must_asciicompat(user);
        u = StringValueCStr(user);
        if (*u) {
            return rb_home_dir_of(user, rb_str_new(0, 0));
        }
    }
    return rb_default_home_dir(rb_str_new(0, 0));

}
mkdir(dirpath, permissions = 0775) → 0 click to toggle source

在底层文件系统中以给定的 permissionsdirpath 创建一个目录;返回零

Dir.mkdir('foo')
File.stat(Dir.new('foo')).mode.to_s(8)[1..4] # => "0755"
Dir.mkdir('bar', 0644)
File.stat(Dir.new('bar')).mode.to_s(8)[1..4] # => "0644"

参见 文件权限。请注意,在 Windows 上会忽略参数 permissions

static VALUE
dir_s_mkdir(int argc, VALUE *argv, VALUE obj)
{
    struct mkdir_arg m;
    VALUE path, vmode;
    int r;

    if (rb_scan_args(argc, argv, "11", &path, &vmode) == 2) {
        m.mode = NUM2MODET(vmode);
    }
    else {
        m.mode = 0777;
    }

    path = check_dirname(path);
    m.path = RSTRING_PTR(path);
    r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_mkdir, &m, RUBY_UBF_IO, 0);
    if (r < 0)
        rb_sys_fail_path(path);

    return INT2FIX(0);
}
new(dirpath) → dir click to toggle source
new(dirpath, encoding: nil) → dir

返回 dirpath 所在目录的新的 Dir 对象

Dir.new('.') # => #<Dir:.>

使用可选关键字参数 encoding 给定的值指定目录条目名称的编码;如果为 nil(默认值),则使用文件系统的编码

Dir.new('.').read.encoding                       # => #<Encoding:UTF-8>
Dir.new('.', encoding: 'US-ASCII').read.encoding # => #<Encoding:US-ASCII>
# File ruby_3_3_0/dir.rb, line 211
def initialize(name, encoding: nil)
  Primitive.dir_initialize(name, encoding)
end
open(dirpath) → dir click to toggle source
open(dirpath, encoding: nil) → dir
open(dirpath) {|dir| ... } → object
open(dirpath, encoding: nil) {|dir| ... } → object

dirpath 所在目录创建一个新的 Dir 对象 dir

如果没有块,则该方法等效于 Dir.new(dirpath, encoding)

Dir.open('.') # => #<Dir:.>

如果给定一个代码块,则使用创建的dir调用该代码块;在代码块退出时,dir将被关闭,并返回代码块的值。

Dir.open('.') {|dir| dir.inspect } # => "#<Dir:.>"

使用可选关键字参数 encoding 给定的值指定目录条目名称的编码;如果为 nil(默认值),则使用文件系统的编码

Dir.open('.').read.encoding                       # => #<Encoding:UTF-8>
Dir.open('.', encoding: 'US-ASCII').read.encoding # => #<Encoding:US-ASCII>
# File ruby_3_3_0/dir.rb, line 183
def self.open(name, encoding: nil, &block)
  dir = Primitive.dir_s_open(name, encoding)
  if block
    begin
      yield dir
    ensure
      Primitive.dir_s_close(dir)
    end
  else
    dir
  end
end
pwd → string 点击切换源代码

返回当前工作目录的路径。

Dir.chdir("/tmp") # => 0
Dir.pwd           # => "/tmp"
static VALUE
dir_s_getwd(VALUE dir)
{
    return rb_dir_getwd();
}
rmdir(dirpath) → 0 点击切换源代码

从底层文件系统中删除 dirpath 处的目录

Dir.rmdir('foo') # => 0

如果目录不为空,则引发异常。

static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
{
    const char *p;
    int r;

    dir = check_dirname(dir);
    p = RSTRING_PTR(dir);
    r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_rmdir, (void *)p, RUBY_UBF_IO, 0);
    if (r < 0)
        rb_sys_fail_path(dir);

    return INT2FIX(0);
}

公共实例方法

chdir → 0 点击切换源代码
chdir { ... } → object

将当前工作目录更改为self

Dir.pwd # => "/"
dir = Dir.new('example')
dir.chdir
Dir.pwd # => "/example"

有块时,临时更改工作目录

  • 调用代码块。

  • 更改到给定的目录。

  • 执行块(不产生参数)。

  • 恢复以前的工作目录。

  • 返回代码块的返回值。

如果可用,则使用Dir.fchdir,否则使用Dir.chdir,有关注意事项,请参阅这些方法。

static VALUE
dir_chdir(VALUE dir)
{
#if defined(HAVE_FCHDIR) && defined(HAVE_DIRFD) && HAVE_FCHDIR && HAVE_DIRFD
    return dir_s_fchdir(rb_cDir, dir_fileno(dir));
#else
    return chdir_path(dir_get(dir)->path, false);
#endif
}
children → array 点击切换源代码

返回self中的条目名称数组,不包括'.''..'

dir = Dir.new('/example')
dir.children # => ["config.h", "lib", "main.rb"]
static VALUE
dir_collect_children(VALUE dir)
{
    VALUE ary = rb_ary_new();
    dir_each_entry(dir, rb_ary_push, ary, TRUE);
    return ary;
}
close → nil 点击切换源代码

关闭self中的流(如果已打开),并返回nil;如果self已关闭,则忽略。

dir = Dir.new('example')
dir.read     # => "."
dir.close     # => nil
dir.close     # => nil
dir.read # Raises IOError.
static VALUE
dir_close(VALUE dir)
{
    struct dir_data *dirp;

    dirp = dir_get(dir);
    if (!dirp->dir) return Qnil;
    closedir(dirp->dir);
    dirp->dir = NULL;

    return Qnil;
}
each {|entry_name| ... } → self 点击切换源代码

使用self中的每个条目名称调用代码块。

Dir.new('example').each {|entry_name| p entry_name }

输出

"."
".."
"config.h"
"lib"
"main.rb"

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

static VALUE
dir_each(VALUE dir)
{
    RETURN_ENUMERATOR(dir, 0, 0);
    return dir_each_entry(dir, dir_yield, Qnil, FALSE);
}
each_child {|entry_name| ... } → self 点击切换源代码

使用self中的每个条目名称调用代码块,不包括'.''..'

dir = Dir.new('/example')
dir.each_child {|entry_name| p entry_name }

输出

"config.h"
"lib"
"main.rb"

如果没有给出代码块,则返回一个枚举器。

static VALUE
dir_each_child_m(VALUE dir)
{
    RETURN_ENUMERATOR(dir, 0, 0);
    return dir_each_entry(dir, dir_yield, Qnil, TRUE);
}
fileno → integer 点击切换源代码

返回dir中使用的文件描述符。

d = Dir.new('..')
d.fileno # => 8

此方法使用POSIX 2008定义的dirfd()函数;该方法在非POSIX平台上未实现(引发NotImplementedError)。

static VALUE
dir_fileno(VALUE dir)
{
    struct dir_data *dirp;
    int fd;

    GetDIR(dir, dirp);
    fd = dirfd(dirp->dir);
    if (fd == -1)
        rb_sys_fail("dirfd");
    return INT2NUM(fd);
}
inspect → string 点击切换源代码

返回self的字符串描述。

Dir.new('example').inspect # => "#<Dir:example>"
static VALUE
dir_inspect(VALUE dir)
{
    struct dir_data *dirp;

    TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
    if (!NIL_P(dirp->path)) {
        VALUE str = rb_str_new_cstr("#<");
        rb_str_append(str, rb_class_name(CLASS_OF(dir)));
        rb_str_cat2(str, ":");
        rb_str_append(str, dirp->path);
        rb_str_cat2(str, ">");
        return str;
    }
    return rb_funcallv(dir, idTo_s, 0, 0);
}
path → string or nil 点击切换源代码

返回用于创建selfdirpath字符串(或nil,如果由方法Dir.for_fd创建)。

Dir.new('example').path # => "example"
static VALUE
dir_path(VALUE dir)
{
    struct dir_data *dirp;

    TypedData_Get_Struct(dir, struct dir_data, &dir_data_type, dirp);
    if (NIL_P(dirp->path)) return Qnil;
    return rb_str_dup(dirp->path);
}
也称为:to_path
pos()

返回self的当前位置;请参阅Dir 作为流状

dir = Dir.new('example')
dir.tell  # => 0
dir.read  # => "."
dir.tell  # => 1
别名为:tell
pos = position → integer 点击切换源代码

self 中设置位置并返回 positionposition 的值应该来自之前对 tell 的调用;如果不是,则后续对 read 的调用的返回值是不确定的。

参见 Dir 作为流式.

示例

dir = Dir.new('example')
dir.pos      # => 0
dir.pos = 3  # => 3
dir.pos      # => 3
dir.pos = 30 # => 30
dir.pos      # => 5
static VALUE
dir_set_pos(VALUE dir, VALUE pos)
{
    dir_seek(dir, pos);
    return pos;
}
read → string or nil 点击切换源代码

读取并返回 self 中的下一个条目名称;如果到达流的末尾,则返回 nil;参见 Dir 作为流式

dir = Dir.new('example')
dir.read # => "."
dir.read # => ".."
dir.read # => "config.h"
static VALUE
dir_read(VALUE dir)
{
    struct dir_data *dirp;
    struct dirent *dp;

    GetDIR(dir, dirp);
    rb_errno_set(0);
    if ((dp = READDIR(dirp->dir, dirp->enc)) != NULL) {
        return rb_external_str_new_with_enc(dp->d_name, NAMLEN(dp), dirp->enc);
    }
    else {
        int e = errno;
        if (e != 0) rb_syserr_fail(e, 0);
        return Qnil;            /* end of stream */
    }
}
rewind → self 点击切换源代码

self 中的位置设置为零;参见 Dir 作为流式

dir = Dir.new('example')
dir.read    # => "."
dir.read    # => ".."
dir.pos     # => 2
dir.rewind  # => #<Dir:example>
dir.pos     # => 0
static VALUE
dir_rewind(VALUE dir)
{
    struct dir_data *dirp;

    GetDIR(dir, dirp);
    rewinddir(dirp->dir);
    return dir;
}
seek(position) → self 点击切换源代码

self 中设置位置并返回 selfposition 的值应该来自之前对 tell 的调用;如果不是,则后续对 read 的调用的返回值是不确定的。

参见 Dir 作为流式.

示例

dir = Dir.new('example')
dir.pos      # => 0
dir.seek(3)  # => #<Dir:example>
dir.pos      # => 3
dir.seek(30) # => #<Dir:example>
dir.pos      # => 5
static VALUE
dir_seek(VALUE dir, VALUE pos)
{
    struct dir_data *dirp;
    long p = NUM2LONG(pos);

    GetDIR(dir, dirp);
    seekdir(dirp->dir, p);
    return dir;
}
tell → integer 点击切换源代码

返回self的当前位置;请参阅Dir 作为流状

dir = Dir.new('example')
dir.tell  # => 0
dir.read  # => "."
dir.tell  # => 1
static VALUE
dir_tell(VALUE dir)
{
    struct dir_data *dirp;
    long pos;

    GetDIR(dir, dirp);
    pos = telldir(dirp->dir);
    return rb_int2inum(pos);
}
别名:pos
to_path()

返回用于创建selfdirpath字符串(或nil,如果由方法Dir.for_fd创建)。

Dir.new('example').path # => "example"
别名:path