класс Dir
Объекты класса Dir представляют собой потоки каталогов, отображающие каталоги в файловой системе. Они предоставляют различные способы перечисления каталогов и их содержимого. Смотрите также File.
Каталог, используемый в этих примерах, содержит две обычные файлы (config.h и main.rb), родительский каталог (..), и сам каталог (.).
Публичные методы класса
# File dir.rb, line 42 def self.[](*args, base: nil, sort: true) Primitive.dir_s_aref(args, base, sort) end
Dir[ string [, string ...] [, base: path] [, sort: true] ] -> array
Эквивалентно вызову Dir.glob([string,...], 0).
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);
}
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 chdir_data args;
args.old_path = rb_str_encode_ospath(rb_dir_getwd());
args.new_path = path;
args.done = FALSE;
return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args);
}
else {
char *p = RSTRING_PTR(path);
int r = (int)(VALUE)rb_thread_call_without_gvl(nogvl_chdir, p,
RUBY_UBF_IO, 0);
if (r < 0)
rb_sys_fail_path(path);
}
return INT2FIX(0);
} Изменяет текущий рабочий каталог процесса на заданную строку. Без аргументов, меняет каталог на значение переменной окружения HOME, или LOGDIR. SystemCallError (вероятно, Errno::ENOENT), если целевой каталог не существует.
Если задан блок, ему передаётся имя нового текущего каталога, и блок выполняется с этим каталогом в качестве текущего. Исходный рабочий каталог восстанавливается по завершении блока. Возвращаемое значение chdir равно значению блока. chdir блоки могут быть вложенными, но в многопоточной программе произойдёт ошибка, если поток попытается открыть chdir блок, в то время как другой поток его открыл, или произойдёт вызов chdir без блока внутри блока, переданного в chdir (даже в одном потоке).
Dir.chdir("/var/spool/mail")
puts Dir.pwd
Dir.chdir("/tmp") do
puts Dir.pwd
Dir.chdir("/usr") do
puts Dir.pwd
end
puts Dir.pwd
end
puts Dir.pwd
выводит:
/var/spool/mail /tmp /usr /tmp /var/spool/mail
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);
} Возвращает массив, содержащий все имена файлов, кроме “.” и “..”, в указанном каталоге. Вызовет SystemCallError, если указанный каталог не существует.
Необязательный ключевой аргумент encoding указывает кодировку каталога. Если не указан, используется кодировка файловой системы.
Dir.children("testdir") #=> ["config.h", "main.rb"]
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);
} Изменяет представление корня файловой системы для этого процесса. Только привилегированный процесс может выполнить этот вызов. Недоступно на всех платформах. На системах Unix см. chroot(2) для получения дополнительной информации.
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);
} Удаляет указанный каталог. Вызывает подкласс SystemCallError, если каталог не пустой.
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;
} Вызывает блок один раз для каждой записи, кроме “.” и “..”, в указанном каталоге, передавая имя файла каждой записи в качестве параметра блоку.
Если блок не задан, возвращается перечислитель вместо него.
Dir.each_child("testdir") {|x| puts "Got #{x}" }
выводит:
Got config.h Got main.rb
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 attrbuf[1] ? Qfalse : Qtrue;
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 (result == Qundef) {
rb_sys_fail_path(orig);
}
return result;
} Возвращает true если указанный файл - пустой каталог, false если это не каталог или не пустой.
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);
} Возвращает массив, содержащий все имена файлов в указанном каталоге. Вызовет SystemCallError, если указанный каталог не существует.
Необязательный ключевой аргумент encoding указывает кодировку каталога. Если не указан, используется кодировка файловой системы.
Dir.entries("testdir") #=> [".", "..", "config.h", "main.rb"]
VALUE
rb_file_directory_p(void)
{
} Возвращает true если указанный файл - каталог, false в противном случае.
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.foreach("testdir") {|x| puts "Got #{x}" }
выводит:
Got . Got .. Got config.h Got main.rb
static VALUE
dir_s_getwd(VALUE dir)
{
return rb_dir_getwd();
} Возвращает путь к текущему рабочему каталогу этого процесса в виде строки.
Dir.chdir("/tmp") #=> 0
Dir.getwd #=> "/tmp"
Dir.pwd #=> "/tmp"
# File dir.rb, line 133 def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true) Primitive.dir_s_glob(pattern, flags, base, sort) end
Dir.glob( pattern, [flags], [base: path] [, sort: true] ) -> array
Dir.glob( pattern, [flags], [base: path] [, sort: true] ) { |filename| block } -> nil Расширяет pattern, являющееся строкой шаблона или Array строк шаблонов, и возвращает массив, содержащий соответствующие имена файлов. Если задан блок, вызывается блок один раз для каждого соответствующего имени файла, передавая имя файла в качестве параметра блоку.
Необязательный base параметр указывает базовый каталог для интерпретации относительных путей вместо текущего рабочего каталога. Поскольку результаты в этом случае не опережаются именем базового каталога, вам потребуется добавить имя базового каталога, если вы хотите получить реальные пути.
Результаты, соответствующие одному символу подстановки или набору символов, сортируются в бинарном порядке по возрастанию, если не указан ложный аргумент в качестве необязательного sort параметра. Порядок Array строк шаблонов и фигурных скобок сохраняется.
Обратите внимание, что шаблон не является регулярным выражением, он больше похож на оболочечный шаблон. См. File::fnmatch для значения параметра flags. Чувствительность к регистру зависит от вашей системы (File::FNM_CASEFOLD игнорируется).
-
* -
Соответствует любому файлу. Может быть ограничен другими значениями в шаблоне. Эквивалентно
/ .* /mxв регулярных выражениях.-
* -
Соответствует всем файлам
-
c* -
Соответствует всем файлам, начинающимся с
c -
*c -
Соответствует всем файлам, заканчивающимся на
c -
*c* -
Соответствует всем файлам, содержащим
c(включая начало или конец).
Обратите внимание, что это не будет соответствовать скрытым файлам (файлам с точкой) в стиле Unix. Чтобы включить их в результаты сопоставления, вы должны использовать флаг File::FNM_DOTMATCH или что-то вроде
"{*,.*}". -
-
** -
Рекурсивно соответствует каталогам, если за ним следует
/. Если этот сегмент пути содержит другие символы, он эквивалентен обычному*. -
? -
Соответствует любому одному символу. Эквивалентно
/.{1}/в регулярных выражениях. -
[set] -
Соответствует любому одному символу в
set. Ведёт себя точно так же, как наборы символов вRegexp, включая отрицание наборов ([^a-z]). -
{p,q} -
Соответствует либо литералу
p, либо литералуq. Эквивалентно альтернации шаблонов в регулярных выражениях.Соответствующие литералы могут иметь длину более одного символа. Может быть указано более двух литералов.
-
\ -
Экранирует следующий метасимвол.
Обратите внимание, что это означает, что вы не можете использовать обратную косую черту в Windows в качестве части шаблона, т.е.
Dir["c:\foo*"]не сработает, используйтеDir["c:/foo*"]вместо этого.
Примеры:
Dir["config.?"] #=> ["config.h"]
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", "main.rb"]
Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"]
Dir.glob(["*.rb", "*.h"]) #=> ["main.rb", "config.h"]
Dir.glob("**/*.rb") #=> ["main.rb",
# "lib/song.rb",
# "lib/song/karaoke.rb"]
Dir.glob("**/*.rb", base: "lib") #=> ["song.rb",
# "song/karaoke.rb"]
Dir.glob("**/lib") #=> ["lib"]
Dir.glob("**/lib/**/*.rb") #=> ["lib/song.rb",
# "lib/song/karaoke.rb"]
Dir.glob("**/lib/*.rb") #=> ["lib/song.rb"]
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));
} Возвращает домашний каталог текущего пользователя или указанного пользователя, если он задан.
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);
} Создает новый каталог с именем string, с разрешениями, указанными необязательным параметром anInteger. Разрешения могут быть изменены значением File::umask, и игнорируются в NT. Вызывает SystemCallError, если каталог не может быть создан. См. также обсуждение разрешений в документации класса для File.
Dir.mkdir(File.join(Dir.home, ".foo"), 0700) #=> 0
# File lib/tmpdir.rb, line 88
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.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, если указано ненулевое значение.
Dir.mktmpdir {|dir| dir is "#{Dir.tmpdir}/d..." }
Dir.mktmpdir(nil, "/var/tmp") {|dir| dir is "/var/tmp/d..." }
Если задан блок, он вызывается с путём каталога. Каталог и его содержимое удаляются с помощью FileUtils.remove_entry перед тем, как Dir.mktmpdir вернёт значение. Возвращается значение блока.
Dir.mktmpdir {|dir|
# use the directory...
open("#{dir}/foo", "w") { ... }
} Если блок не указан, возвращается путь к каталогу. В этом случае Dir.mktmpdir не удаляет каталог.
dir = Dir.mktmpdir
begin
# use the directory...
open("#{dir}/foo", "w") { ... }
ensure
# remove the directory.
FileUtils.remove_entry dir
end # File dir.rb, line 34 def initialize(name, encoding: nil) Primitive.dir_initialize(name, encoding) end
Dir.new( string ) -> aDir Dir.new( string, encoding: enc ) -> aDir
Возвращает новый объект каталога для указанного каталога.
Необязательный параметр encoding указывает кодировку каталога. Если не указано, используется кодировка файловой системы.
# File dir.rb, line 14
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.open( string ) -> aDir
Dir.open( string, encoding: enc ) -> aDir
Dir.open( string ) {| aDir | block } -> anObject
Dir.open( string, encoding: enc ) {| aDir | block } -> anObject Необязательный параметр encoding указывает кодировку каталога. Если не указано, используется кодировка файловой системы.
Без блока, open является синонимом Dir::new. Если присутствует блок, ему передаётся aDir в качестве параметра. Каталог закрывается в конце блока, и Dir::open возвращает значение блока.
static VALUE
dir_s_getwd(VALUE dir)
{
return rb_dir_getwd();
} Возвращает путь к текущему рабочему каталогу данного процесса в виде строки.
Dir.chdir("/tmp") #=> 0
Dir.getwd #=> "/tmp"
Dir.pwd #=> "/tmp"
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);
} Удаляет указанный каталог. Вызывает подкласс SystemCallError, если каталог не пуст.
# File lib/tmpdir.rb, line 21
def self.tmpdir
tmp = nil
['TMPDIR', 'TMP', 'TEMP', ['system temporary path', @@systmpdir], ['/tmp']*2, ['.']*2].each do |name, dir = ENV[name]|
next if !dir
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
tmp = dir
break
end
end
raise ArgumentError, "could not find a temporary directory" unless tmp
tmp
end Возвращает путь временного файла операционной системы.
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);
} Удаляет указанный каталог. Вызывает подкласс SystemCallError, если каталог не пуст.
Методы публичного экземпляра
static VALUE
dir_collect_children(VALUE dir)
{
VALUE ary = rb_ary_new();
dir_each_entry(dir, rb_ary_push, ary, TRUE);
return ary;
} Возвращает массив, содержащий все имена файлов, кроме «.» и «..» в этом каталоге.
d = Dir.new("testdir")
d.children #=> ["config.h", "main.rb"]
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;
} Закрывает поток каталога. Вызов этого метода для закрытого объекта Dir игнорируется с Ruby 2.3.
d = Dir.new("testdir")
d.close #=> nil
static VALUE
dir_each(VALUE dir)
{
RETURN_ENUMERATOR(dir, 0, 0);
return dir_each_entry(dir, dir_yield, Qnil, FALSE);
} Вызывает блок один раз для каждой записи в этом каталоге, передавая имя файла каждой записи в качестве параметра блоку.
Если блок не указан, вместо него возвращается итератор.
d = Dir.new("testdir")
d.each {|x| puts "Got #{x}" }
Результат:
Got . Got .. Got config.h Got main.rb
static VALUE
dir_each_child_m(VALUE dir)
{
RETURN_ENUMERATOR(dir, 0, 0);
return dir_each_entry(dir, dir_yield, Qnil, TRUE);
} Вызывает блок один раз для каждой записи, кроме «.» и «..» в этом каталоге, передавая имя файла каждой записи в качестве параметра блоку.
Если блок не указан, вместо него возвращается итератор.
d = Dir.new("testdir")
d.each_child {|x| puts "Got #{x}" }
Результат:
Got config.h Got main.rb
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);
} Возвращает дескриптор файла, используемый в dir.
d = Dir.new("..")
d.fileno #=> 8
Этот метод использует функцию dirfd(), определённую POSIX 2008. NotImplementedError возникает на других платформах, таких как Windows, которые не предоставляют эту функцию.
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);
} Возвращает строку, описывающую этот объект Dir.
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);
} Возвращает путь, переданный конструктору dir.
d = Dir.new("..")
d.path #=> ".."
Возвращает текущую позицию в dir. Смотрите также Dir#seek.
d = Dir.new("testdir")
d.tell #=> 0
d.read #=> "."
d.tell #=> 12
static VALUE
dir_set_pos(VALUE dir, VALUE pos)
{
dir_seek(dir, pos);
return pos;
} Синоним для Dir#seek, но возвращает параметр позиции.
d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
d.read #=> "."
i = d.pos #=> 12
d.read #=> ".."
d.pos = i #=> 12
d.read #=> ".."
static VALUE
dir_read(VALUE dir)
{
struct dir_data *dirp;
struct dirent *dp;
GetDIR(dir, dirp);
errno = 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 */
}
} Читает следующую запись из dir и возвращает её как строку. Возвращает nil в конце потока.
d = Dir.new("testdir")
d.read #=> "."
d.read #=> ".."
d.read #=> "config.h"
static VALUE
dir_rewind(VALUE dir)
{
struct dir_data *dirp;
GetDIR(dir, dirp);
rewinddir(dirp->dir);
return dir;
} Перемещает dir к первой записи.
d = Dir.new("testdir")
d.read #=> "."
d.rewind #=> #<Dir:0x401b3fb0>
d.read #=> "."
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;
} Перемещает указатель в определённое место в dir. целое число должно быть значением, возвращённым Dir#tell.
d = Dir.new("testdir") #=> #<Dir:0x401b3c40>
d.read #=> "."
i = d.tell #=> 12
d.read #=> ".."
d.seek(i) #=> #<Dir:0x401b3c40>
d.read #=> ".."
static VALUE
dir_tell(VALUE dir)
{
struct dir_data *dirp;
long pos;
GetDIR(dir, dirp);
pos = telldir(dirp->dir);
return rb_int2inum(pos);
} Возвращает текущую позицию в dir. Смотрите также Dir#seek.
d = Dir.new("testdir")
d.tell #=> 0
d.read #=> "."
d.tell #=> 12
Возвращает путь, переданный конструктору dir.
d = Dir.new("..")
d.path #=> ".."
Ruby Core © 1993–2020 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.