класс 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.
Публичные методы класса
Source
# 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; возвращает массив выбранных имен записей.
Source
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 (даже в том же потоке).
Вызывает исключение, если целевой каталог не существует.
Source
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>
См. String Encoding.
Вызывает исключение, если каталог не существует.
Source
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.
Source
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
Вызывает исключение, если каталог не пуст.
Source
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, за исключением того, что записи '.' и '..' не включены.
Source
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 не указывает на каталог или файл в базовой файловой системе.
Source
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>
См. String Encoding.
Вызывает исключение, если каталог не существует.
Source
VALUE
rb_file_directory_p(void)
{
} Возвращает, является ли dirpath каталогом в базовой файловой системе:
Dir.exist?('/example') # => true
Dir.exist?('/nosuch') # => false
Dir.exist?('/example/main.rb') # => false
То же самое, что File.directory?.
Source
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 позволяет избежать уязвимости 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 = 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: '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 = 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; метод не реализован на непозиксных платформах (возбуждает 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);
if((pos = telldir(dirp->dir)) < 0)
rb_sys_fail("telldir");
return rb_int2inum(pos);
} Возвращает текущую позицию self; см. Dir As Stream-Like:
dir = Dir.new('example')
dir.tell # => 0
dir.read # => "."
dir.tell # => 1
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.