Dir 类
Dir 类的对象表示底层文件系统中的目录。
它主要包含
-
创建对象时给出的字符串path,它指定底层文件系统中的目录;方法
path
返回路径。
关于示例¶ ↑
本页的一些示例使用这个简单的文件树
example/ ├── config.h ├── lib/ │ ├── song/ │ │ └── karaoke.rb │ └── song.rb └── main.rb
其他示例使用 Ruby 项目本身 的文件树。
Dir 作为类数组¶ ↑
Dir 对象在某些方面类似数组
-
它有实例方法
children
、each
和each_child
。 -
它包含 模块 Enumerable。
Dir 作为类似流¶ ↑
Dir 对象在某些方面类似于流。
流最初打开用于读取,但可以手动关闭(使用 close
方法),如果通过使用块调用的 Dir.open
创建,则在块退出时关闭。已关闭的流不能进一步操作,也不能重新打开。
流有一个位置,它是目录中某个条目的索引
-
初始位置为零(在第一个条目之前)。
-
方法
pos=
设置位置(但忽略流之外的值),并返回位置。 -
方法
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
-
继承自 类 Object。
-
包含 模块 Enumerable,该模块提供了几十个其他方法。
此处,类 Dir 提供了对以下内容有用的方法
读取¶ ↑
-
close
:关闭self
的目录流。 -
pos=
:设置self
的目录流中的位置。 -
read
:读取并返回self
的目录流中的下一个条目。 -
rewind
:将self
的目录流中的位置设置为第一个条目。 -
seek
:将self
的目录流中的位置设置为给定偏移处的条目。
设置¶ ↑
查询¶ ↑
-
::children
:返回给定目录的子项(文件和目录)的名称数组,但不包括.
或..
。 -
::empty?
:返回给定路径是否为空目录。 -
::entries
:返回给定目录的子项(文件和目录)的名称数组,包括.
和..
。 -
::exist?
:返回给定路径是否是目录。 -
::getwd
(别名为 pwd):返回当前工作目录的路径。 -
::glob
:返回与给定模式和标志匹配的文件路径数组。 -
::home
:返回给定用户或当前用户的 home 目录路径。 -
children
:返回self
的子项(文件和目录)的名称数组,但不包括.
或..
。 -
fileno
:返回self
的整数文件描述符。
迭代¶ ↑
-
::each_child
:使用给定目录中的每个条目调用给定的块,但不包括.
或..
。 -
::foreach
:使用给定目录中的每个条目调用给定的块,包括.
和..
。 -
each
:使用self
中的每个条目调用给定的块,包括.
和..
。 -
each_child
:使用self
中的每个条目调用给定的块,但不包括.
或..
。
其他¶ ↑
常量
- SYSTMPDIR
系统临时目录路径
公共类方法
使用参数 patterns
以及关键字参数 base
和 sort
的值调用 Dir.glob
;返回选定条目名称的数组。
# File dir.rb, line 222 def self.[](*args, base: nil, sort: true) Primitive.dir_s_aref(args, base, sort) end
更改当前工作目录。
带有参数 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
的块中发生没有块的 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); }
返回 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); }
将调用进程的根目录更改为 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); }
从底层文件系统中移除 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); }
与 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; }
返回 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; }
返回 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); }
返回 dirpath
是否是底层文件系统中的目录
Dir.exist?('/example') # => true Dir.exist?('/nosuch') # => false Dir.exist?('/example/main.rb') # => false
与 File.directory?
相同。
VALUE rb_file_directory_p(void) { }
将当前工作目录更改为由整数文件描述符 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
的块中发生没有块的 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); }
返回一个新的 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; }
使用 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; }
返回当前工作目录的路径
Dir.chdir("/tmp") # => 0 Dir.pwd # => "/tmp"
static VALUE dir_s_getwd(VALUE dir) { return rb_dir_getwd(); }
根据参数形成条目名称的数组 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;表现得像 正则表达式交替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
中定义的一个或多个常量的按位 OR。
示例
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;表现得像 正则表达式并集(例如,'(?:a|b)'
)pattern = '{LEGAL,BSDL}' Dir.glob(pattern) # => ["LEGAL", "BSDL"]
-
File::FNM_NOESCAPE:指定使用反斜杠字符
'\'
转义已禁用;该字符不是转义字符。 -
File::FNM_PATHNAME:指定元字符
'*'
和'?'
不匹配目录分隔符。 -
File::FNM_SHORTNAME:指定如果模式存在,它们可以匹配短名称;仅限 Windows。
# File 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
如果user_name
不为nil
,则返回使用user_name
指定的用户的 home 目录路径,否则返回当前登录用户
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)); }
在dirpath
的底层文件系统中使用给定的permissions
创建一个目录;返回零
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); }
Dir.mktmpdir
创建临时目录。
该目录以 0700 权限创建。应用程序不应更改权限,以使其他用户可以访问临时目录。
目录名称的前缀和后缀由可选第一个参数prefix_suffix指定。
-
如果未指定或为 nil,则“d”用作前缀,且不使用后缀。
-
如果它是一个字符串,则它用作前缀,且不使用后缀。
-
如果它是一个数组,则第一个元素用作前缀,第二个元素用作后缀。
Dir.mktmpdir {|dir| dir is ".../d..." } Dir.mktmpdir("foo") {|dir| dir is ".../foo..." } Dir.mktmpdir(["foo", "bar"]) {|dir| dir is ".../foo...bar" }
该目录在Dir.tmpdir
或可选的第二个参数tmpdir(如果给出了非 nil 值)下创建。
Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." } Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." }
如果给出了一个块,则使用目录的路径对其进行生成。在Dir.mktmpdir
返回之前,使用FileUtils.remove_entry
删除目录及其内容。返回块的值。
Dir.mktmpdir {|dir| # use the directory... open("#{dir}/foo", "w") { something using the file } }
如果未给出块,则返回目录的路径。在这种情况下,Dir.mktmpdir
不会删除目录。
dir = Dir.mktmpdir begin # use the directory... open("#{dir}/foo", "w") { something using the file } ensure # remove the directory. FileUtils.remove_entry dir end
# File lib/tmpdir.rb, line 91 def self.mktmpdir(prefix_suffix=nil, *rest, **options) base = nil path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|path, _, _, d| base = d mkdir(path, 0700) } if block_given? begin yield path.dup ensure unless base stat = File.stat(File.dirname(path)) if stat.world_writable? and !stat.sticky? raise ArgumentError, "parent directory is world writable but not sticky" end end FileUtils.remove_entry path end else path end end
返回一个新的 Dir 对象,用于 dirpath
处的目录
Dir.new('.') # => #<Dir:.>
使用可选关键字参数 encoding
提供的值指定目录条目名称的编码;如果为 nil
(默认值),则使用文件系统的编码
Dir.new('.').read.encoding # => #<Encoding:UTF-8> Dir.new('.', encoding: 'US-ASCII').read.encoding # => #<Encoding:US-ASCII>
# File dir.rb, line 211 def initialize(name, encoding: nil) Primitive.dir_initialize(name, encoding) end
为 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 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
返回当前工作目录的路径
Dir.chdir("/tmp") # => 0 Dir.pwd # => "/tmp"
static VALUE dir_s_getwd(VALUE dir) { return rb_dir_getwd(); }
从底层文件系统中移除 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); }
返回操作系统的临时文件路径。
# File lib/tmpdir.rb, line 26 def self.tmpdir ['TMPDIR', 'TMP', 'TEMP', ['system temporary path', SYSTMPDIR], ['/tmp']*2, ['.']*2].find do |name, dir| unless dir next if !(dir = ENV[name] rescue next) or dir.empty? end dir = File.expand_path(dir) stat = File.stat(dir) rescue next case when !stat.directory? warn "#{name} is not a directory: #{dir}" when !stat.writable? warn "#{name} is not writable: #{dir}" when stat.world_writable? && !stat.sticky? warn "#{name} is world-writable: #{dir}" else break dir end end or raise ArgumentError, "could not find a temporary directory" end
从底层文件系统中移除 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); }
公共实例方法
将当前工作目录更改为 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 }
返回 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; }
如果 self
已打开,则关闭 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; }
使用 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); }
使用 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); }
返回在 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); }
返回 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); }
返回用于创建 self
的 dirpath
字符串(或如果由 Dir.for_fd
方法创建,则返回 nil
)
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); }
设置 self
中的位置并返回 position
。position
的值应该由对 tell
的早期调用返回;如果不是,则对 read
的后续调用的返回值未指定。
请参见 Dir As Stream-Like。
示例
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; }
从 self
读取并返回下一个条目名称;如果在流的末尾,则返回 nil
;请参见 Dir As Stream-Like
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 */ } }
将 self
中的位置设置为零;请参见 Dir As Stream-Like
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; }
设置 self
中的位置并返回 self
。position
的值应该由对 tell
的早期调用返回;如果不是,则对 read
的后续调用的返回值未指定。
请参见 Dir As Stream-Like。
示例
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; }
返回 self
的当前位置;参见 Dir As Stream-Like
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); }