класс 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:
-
Наследуется от класса Объект.
-
Включает модуль Enumerable, который предоставляет десятки дополнительных методов.
Здесь класс Dir предоставляет методы, полезные для:
Чтение
-
close: Закрывает поток каталога дляself. -
pos=: Устанавливает позицию в потоке каталога дляself. -
read: Читает и возвращает следующий элемент в потоке каталога дляself. -
rewind: Устанавливает позицию в потоке каталога дляselfв первый элемент. -
seek: Устанавливает позицию в потоке каталога дляselfэлемента по заданному смещению.
Установка
-
::chdir: Изменяет текущую рабочую директорию процесса на заданную директорию. -
::chroot: Изменяет корень файловой системы для текущего процесса на заданную директорию.
Запрос
-
::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.
Константы
- SYSTMPDIR
-
Путь к системной временной директории
Публичные методы класса
# 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 (chroot(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 = (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);
} Удаляет каталог по пути 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,};
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 на пустой каталог:
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_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);
} Изменяет текущий рабочий каталог на каталог, указанный целочисленным дескриптором файла fd.
При передаче дескриптора файла через сокет UNIX или дочернему процессу, использование fchdir вместо chdir позволяет избежать уязвимости time-of-check to time-of-use
Без блока, изменяет на каталог, заданный 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; метод не реализован на непозиксных платформах (вызывает 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 = fdopendir(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; метод не реализован на непозиксных платформах (вызывает 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.dir_s_glob(pattern, flags, base, sort) end
Создаёт массив имен_элементов имён элементов, выбранных по заданным аргументам.
Аргумент patterns — строковый шаблон или массив строковых шаблонов; обратите внимание, что это не регулярные выражения; см. ниже.
Примечания к следующим примерам:
-
'*'— шаблон, который соответствует любому имени элемента, за исключением тех, которые начинаются с'.'. -
Мы используем метод
Array#take, чтобы сократить возвращаемые массивы, которые в противном случае были бы очень большими.
Без блока возвращает массив имен_элементов; пример (используя простую древовидную структуру файлов):
Dir.glob('*') # => ["config.h", "lib", "main.rb"]
С блоком вызывает блок с каждым из имен_элементов и возвращает 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]': Соответствует любому символу в строке множество; ведёт себя как класс символов Regexp, включая отрицание множества ('[^a-z]'):Dir.glob('*.[a-z][a-z]').take(3) # => ["CONTRIBUTING.md", "COPYING.ja", "KNOWNBUGS.rb"] -
'{abc,xyz}': Соответствует либо строке abc, либо строке xyz; ведёт себя как альтернатива Regexp: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 (например,'(?: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)) {
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));
} Возвращает путь к домашнему каталогу пользователя, указанного 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 = (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);
} Создаёт каталог в файловой системе по адресу 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 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.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") { 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: '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 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: '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 = (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);
} Удаляет каталог по пути dirpath из базовой файловой системы:
Dir.rmdir('foo') # => 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 Возвращает путь к временному файлу операционной системы.
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);
} Удаляет каталог по пути 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;
closedir(dirp->dir);
dirp->dir = NULL;
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 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_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 As Stream-Like:
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 As Stream-Like:
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 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_tell(VALUE dir)
{
struct dir_data *dirp;
long pos;
GetDIR(dir, dirp);
pos = telldir(dirp->dir);
return rb_int2inum(pos);
} Возвращает текущую позицию self; см. Dir As Stream-Like:
dir = Dir.new('example')
dir.tell # => 0
dir.read # => "."
dir.tell # => 1
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.