класс Dir
Объект класса Dir представляет каталог в базовой файловой системе.
В основном он состоит из:
-
Строкового пути, задаваемого при создании объекта и указывающего на каталог в базовой файловой системе; метод
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=задаёт позицию (но игнорирует значение за пределами потока) и возвращает позицию. -
Метод
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:
-
Наследуется от класса Object.
-
Подключает модуль Enumerable, предоставляющий десятки дополнительных методов.
Класс 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.
Публичные методы класса
# File dir.rb, line 222 def self.[](*args, base: nil, sort: true) Primitive.dir_s_aref(args, base, sort) end
Вызывает Dir.glob с аргументом patterns и значениями ключевых аргументов base и sort; возвращает массив выбранных имён записей.
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);
} Изменяет текущий рабочий каталог.
С аргументом 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_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, исключая '.' и '..'; задаёт указанную кодировку для каждого возвращённого имени записи:
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_chroot(VALUE dir, VALUE path)
{
path = check_dirname(path);
if (IO_WITHOUT_GVL_INT(nogvl_chroot, (void *)RSTRING_PTR(path)) == -1)
rb_sys_fail_path(path);
return INT2FIX(0);
} Изменяет корневой каталог вызывающего процесса на каталог, указанный в dirpath. Новый корневой каталог используется для путей, начинающихся с '/'. Корневой каталог наследуется всеми дочерними процессами вызывающего процесса.
Вызывать chroot может только привилегированный процесс.
См. Linux chroot.
static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
{
const char *p;
int r;
dir = check_dirname(dir);
p = RSTRING_PTR(dir);
r = IO_WITHOUT_GVL_INT(nogvl_rmdir, (void *)p);
if (r < 0)
rb_sys_fail_path(dir);
return INT2FIX(0);
} Удаляет каталог по пути dirpath из базовой файловой системы:
Dir.rmdir('foo') # => 0
Вызывает исключение, если каталог не пуст.
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.foreach, за исключением того, что записи '.' и '..' не включаются.
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,};
struct getattrlist_args args = GETATTRLIST_ARGS(&al, attrbuf, 0);
if (gvl_getattrlist(&args, path) != 0)
rb_sys_fail_path(orig);
if (*(const fsobj_tag_t *)(attrbuf+1) == VT_HFS) {
al.commonattr = 0;
al.dirattr = ATTR_DIR_ENTRYCOUNT;
if (gvl_getattrlist(&args, path) == 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)IO_WITHOUT_GVL(nogvl_dir_empty_p, (void *)path);
if (FIXNUM_P(result)) {
rb_syserr_fail_path((int)FIX2LONG(result), orig);
}
return result;
} Возвращает значение, указывающее, задаёт ли dirpath пустой каталог:
dirpath = '/tmp/foo'
Dir.mkdir(dirpath)
Dir.empty?(dirpath) # => true
Dir.empty?('/example') # => false
Dir.empty?('/example/main.rb') # => false
Вызывает исключение, если dirpath не задаёт каталог или файл в базовой файловой системе.
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.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>
См. Кодировка строк.
Вызывает исключение, если каталог не существует.
VALUE
rb_file_directory_p(void)
{
} Возвращает значение, указывающее, является ли dirpath каталогом в базовой файловой системе:
Dir.exist?('/example') # => true
Dir.exist?('/nosuch') # => false
Dir.exist?('/example/main.rb') # => false
То же, что и File.directory?.
static VALUE
dir_s_fchdir(VALUE klass, VALUE fd_value)
{
int fd = RB_NUM2INT(fd_value);
if (chdir_alone_block_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 = IO_WITHOUT_GVL_INT(nogvl_fchdir, &fd);
if (r < 0)
rb_sys_fail("fchdir");
}
return INT2FIX(0);
} Изменяет текущий рабочий каталог на каталог, указанный целочисленным дескриптором файла 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"
Этот метод использует функцию fchdir(), определённую стандартом POSIX 2008; метод не реализован на платформах, не поддерживающих POSIX (вызывает NotImplementedError).
Вызывает исключение, если дескриптор файла недействителен.
В многопоточной программе возникает ошибка, если поток пытается открыть блок chdir, когда другой поток уже открыл такой блок, или если вызов chdir без блока выполняется внутри блока, переданного в chdir (даже в том же потоке).
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 = IO_WITHOUT_GVL(nogvl_fdopendir, (void *)(VALUE)NUM2INT(fd)))) {
rb_sys_fail("fdopendir");
UNREACHABLE_RETURN(Qnil);
}
RB_OBJ_WRITE(dir, &dp->path, Qnil);
return dir;
} Возвращает новый объект Dir, представляющий каталог, указанный заданным целочисленным дескриптором файла каталога fd:
d0 = Dir.new('..')
d1 = Dir.for_fd(d0.fileno)
Обратите внимание, что у возвращённого d1 нет связанного пути:
d0.path # => '..' d1.path # => nil
Этот метод использует функцию fdopendir(), определённую стандартом POSIX 2008; метод не реализован на платформах, не поддерживающих POSIX (вызывает NotImplementedError).
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;
} Вызывает блок для каждого имени записи в каталоге по пути 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_s_getwd(VALUE dir)
{
return rb_dir_getwd();
} Возвращает путь к текущему рабочему каталогу:
Dir.chdir("/tmp") # => 0
Dir.pwd # => "/tmp"
# File dir.rb, line 410 def self.glob(pattern, _flags = 0, flags: _flags, base: nil, sort: true) Primitive.attr! :use_block Primitive.dir_s_glob(pattern, flags, base, sort) end
Формирует массив 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.
Пример:
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.
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)) {
StringValue(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));
} Возвращает путь к домашнему каталогу пользователя, указанного в user_name, если он не равен nil, или текущего пользователя системы:
Dir.home # => "/home/me"
Dir.home('root') # => "/root"
Вызывает ArgumentError, если user_name не является именем пользователя.
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 = IO_WITHOUT_GVL_INT(nogvl_mkdir, &m);
if (r < 0)
rb_sys_fail_path(path);
return INT2FIX(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"
См. Права доступа к файлам. Обратите внимание, что аргумент permissions игнорируется в Windows.
# File lib/tmpdir.rb, line 97
def self.mktmpdir(prefix_suffix=nil, *rest, **options, &block)
base = nil
path = Tmpname.create(prefix_suffix || "d", *rest, **options) {|path, _, _, d|
base = d
mkdir(path, 0700)
}
if block
begin
yield path.dup
ensure
unless base
base = File.dirname(path)
stat = File.stat(base)
if stat.world_writable? and !stat.sticky?
raise ArgumentError, "parent directory is world writable but not sticky: #{base}"
end
end
FileUtils.remove_entry path
end
else
path
end
end Dir.mktmpdir создаёт временный каталог.
require 'tmpdir'
Dir.mktmpdir {|dir|
# use the directory
}
Каталог создаётся с правами доступа 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") { 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 dir.rb, line 211 def initialize(name, encoding: nil) Primitive.dir_initialize(name, encoding) end
Возвращает новый объект Dir для каталога по пути dirpath:
Dir.new('.') # => #<Dir:.>
Значение необязательного ключевого аргумента encoding задаёт кодировку имён записей каталога; если значение равно nil (по умолчанию), используется кодировка файловой системы:
Dir.new('.').read.encoding # => #<Encoding:UTF-8>
Dir.new('.', encoding: Encoding::US_ASCI).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 dir для каталога по пути dirpath.
Без блока метод эквивалентен 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: Encoding::US_ASCII).read.encoding # => #<Encoding:US-ASCII>
static VALUE
dir_s_getwd(VALUE dir)
{
return rb_dir_getwd();
} Возвращает путь к текущему рабочему каталогу:
Dir.chdir("/tmp") # => 0
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 = IO_WITHOUT_GVL_INT(nogvl_rmdir, (void *)p);
if (r < 0)
rb_sys_fail_path(dir);
return INT2FIX(0);
} Удаляет каталог по пути dirpath из базовой файловой системы:
Dir.rmdir('foo') # => 0
Вызывает исключение, если каталог не пуст.
# File lib/tmpdir.rb, line 25
def self.tmpdir
Tmpname::TMPDIR_CANDIDATES.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 !File.writable?(dir)
# We call File.writable?, not stat.writable?, because you can't tell if a dir is actually
# writable just from stat; OS mechanisms other than user/group/world bits can affect this.
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 Возвращает путь к временному каталогу операционной системы.
require 'tmpdir' Dir.tmpdir # => "/tmp"
static VALUE
dir_s_rmdir(VALUE obj, VALUE dir)
{
const char *p;
int r;
dir = check_dirname(dir);
p = RSTRING_PTR(dir);
r = IO_WITHOUT_GVL_INT(nogvl_rmdir, (void *)p);
if (r < 0)
rb_sys_fail_path(dir);
return INT2FIX(0);
} Удаляет каталог по пути dirpath из базовой файловой системы:
Dir.rmdir('foo') # => 0
Вызывает исключение, если каталог не пуст.
Открытые методы экземпляра
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.pwd # => "/"
dir = Dir.new('example')
dir.chdir
Dir.pwd # => "/example"
При наличии блока временно изменяет рабочий каталог:
-
Вызывает блок.
-
Переходит в указанный каталог.
-
Выполняет блок (без передачи аргументов).
-
Восстанавливает предыдущий рабочий каталог.
-
Возвращает значение, возвращённое блоком.
Использует Dir.fchdir, если этот метод доступен, и Dir.chdir в противном случае; ограничения описаны в документации этих методов.
static VALUE
dir_collect_children(VALUE dir)
{
VALUE ary = rb_ary_new();
dir_each_entry(dir, rb_ary_push, ary, TRUE);
return ary;
} Возвращает массив имён записей в self, кроме '.' и '..':
dir = Dir.new('/example')
dir.children # => ["config.h", "lib", "main.rb"]
static VALUE
dir_close(VALUE dir)
{
struct dir_data *dirp;
dirp = dir_get(dir);
if (!dirp->dir) return Qnil;
close_dir_data(dirp);
return Qnil;
} Закрывает поток в self, если он открыт, и возвращает nil; если self уже закрыт, ничего не делает:
dir = Dir.new('example')
dir.read # => "."
dir.close # => nil
dir.close # => nil
dir.read # Raises IOError.
static VALUE
dir_each(VALUE dir)
{
RETURN_ENUMERATOR(dir, 0, 0);
return dir_each_entry(dir, dir_yield, Qnil, FALSE);
} Вызывает блок для каждого имени записи в self:
Dir.new('example').each {|entry_name| p entry_name }
Вывод:
"." ".." "config.h" "lib" "main.rb"
Если блок не задан, возвращает Enumerator.
static VALUE
dir_each_child_m(VALUE dir)
{
RETURN_ENUMERATOR(dir, 0, 0);
return dir_each_entry(dir, dir_yield, Qnil, TRUE);
} Вызывает блок для каждого имени записи в self, кроме '.' и '..':
dir = Dir.new('/example')
dir.each_child {|entry_name| p entry_name }
Вывод:
"config.h" "lib" "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; метод не реализован на платформах, отличных от POSIX (вызывает исключение NotImplementedError).
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:
Dir.new('example').inspect # => "#<Dir: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);
} Возвращает строку dirpath, использованную для создания self (или nil, если объект создан методом Dir.for_fd):
Dir.new('example').path # => "example"
static VALUE
dir_set_pos(VALUE dir, VALUE pos)
{
dir_seek(dir, pos);
return pos;
} Устанавливает позицию в self и возвращает position. Значение position должно быть возвращено при предыдущем вызове tell; в противном случае возвращаемые значения последующих вызовов read не определены.
См. Каталог как поток.
Примеры:
dir = Dir.new('example')
dir.pos # => 0
dir.pos = 3 # => 3
dir.pos # => 3
dir.pos = 30 # => 30
dir.pos # => 5
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; возвращает nil при достижении конца потока; см. Каталог как поток:
dir = Dir.new('example')
dir.read # => "."
dir.read # => ".."
dir.read # => "config.h"
static VALUE
dir_rewind(VALUE dir)
{
struct dir_data *dirp;
GetDIR(dir, dirp);
rewinddir(dirp->dir);
return dir;
} Устанавливает позицию в self на ноль; см. Каталог как поток:
dir = Dir.new('example')
dir.read # => "."
dir.read # => ".."
dir.pos # => 2
dir.rewind # => #<Dir:example>
dir.pos # => 0
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 и возвращает self. Значение position должно быть возвращено при предыдущем вызове tell; в противном случае возвращаемые значения последующих вызовов read не определены.
См. Каталог как поток.
Примеры:
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_tell(VALUE dir)
{
struct dir_data *dirp;
long pos;
GetDIR(dir, dirp);
if((pos = telldir(dirp->dir)) < 0)
rb_sys_fail("telldir");
return rb_int2inum(pos);
} Возвращает текущую позицию self; см. Каталог как поток:
dir = Dir.new('example')
dir.tell # => 0
dir.read # => "."
dir.tell # => 1
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.