Чтение, запись и удаление файлов
Чтение файлов
Давайте предположим, что в нашей файловой системе есть файл example.txt
, который содержит следующее:
Первое, что необходимо сделать для того, чтобы прочитать содержимое, это открыть файл. Открытие файла принимает 2 аргумента: путь до файла и права на этот файл
Можно выделить 3 основных права на файл:
r
- read/чтениеa
- append/добавление (мы можем добавить в файл значение, но не можем изменить уже существующее)w
- write/запись
Кроме того, права указаны в порядке суммирования, что означает, что каждый пункт будет помимо своих собственных прав иметь еще и права на из пункта выше.
После того как мы открыли файл нам доступны следующие методы:
read
- перенос значения в строкове представление. При этом наши переносы строки, пробелы, табуляции сохраняютсяreadlines
- перенос значения в массив строк, где каждая новая строка будет новым значением в массивеeach_line
- возвращает объектEnumerator
. Если открыть в нем блок кода, то можно проитерировать каждую строчку файлаreadline
- читает строку в файле и при следующем вызове этого же метода будет прочитана следующая строкаseek
- перевод курсора к указанной позиции в файле. Принимает первым аргументом размер отступа, а вторым от чего именно будет отступ::END
- с конца:SET
- с начала:CUR
- от текущей позиции
size
- размер файла в байтахbirthtime
- дата создания объектаatime
- дата последнего доступа к файлу
Важно понимать отличие между readlines
и each_line
с readline
. reeadlines
читает содержимое файла целиком и целиком помещает его в массив. Это может быть эффективно при работе с небольшими файлами, но если файл весит 1 ГБ, то весь 1ГБ будет помещен в память компьютера, а как мы знаем размеры памяти куда более ограничены по сравнению с постоянной памятью по типу SSD или HHD. each_line
и readline
отличается своей возможностью лениво
читать файл. Если текущая итерация обрабатвает 1 строчку файла, то остальные строчки не будут помещены в память. Когда итерация начнет обрабатывать 2 строчку, то данные из первой строки очистятся из памяти, а данные из 3 и последующей не будут в нее загружены.
После завершения работы нам необходимо всегда закрывать работу файла вызвав у него метод close
. Кроме того, мы можем не вызывать этот метод, если будет работать с файлом внутри блока при открытии, т.к. закрытие файла будет вызвано автоматически по окончанию работы блока кода:
Изменение файлов
Давайте сразу на примере посмотрим как мы можем записывать в файл:
Обратите внимание, в примере выше запись в файл всегда будет перезаписывать уже существующие данные. Для того, чтобы нам вместо перезаписи дополнять данными пользуются флагом a
при записи
Такой же результат мы получим, если откроем файл с правами a
Помимо методов объекта существуют еще полезные методы класса, которые могут являться клонами метода объекта, либо дают новый функционал. Вот наиболее часто встречающиеся методы:
File.rename
- переименновать файлFile.size
- получить размер файла в байтахFile.exists?
- существует ли файлFile.directory?
- является ли файл директориейFile.file?
- является ли файл файломFile.foreach
- такой же функционал как и у метода объекта.each_line
File.read
- такой же функционал как и у метода объекта.read
File.readlines
- такой же функционал как и у метода объекта.readlines
Также, методы класса самотоятельно открывают и закрывают файл, соответсвенно, нам об этом заботиться не нужно.
Работа с директорией
С файлами мы разобрались, но что делать, когда мы хотим работать сразу с несколькими файлами, объеденных в одной директории ? Для этого у нас есть класс Dir
со своимсобственным функционалом. Вот несколько наиболее полезных классовых методов у него:
Dir.mkdir
- создание новой директории. Внимание этот метод не создает вложнные каталоги. Если мы попытаемся создат ькаталог в несуществующем каталоге, то получим ошибку.Dir.entries
- возвращает массив названий файлов и каталогов в указаной директории. Учтите6 что это именно массив названий файлов, а не объектовFile
.Dir.glob
- Возвращает список файлов и директорий по паттерн матчингу.*
обозначает любое количество символов, включая ноль символов.**
обозначает любое количество символов, включая вложенные каталоги. Кроме символа * также используются символы?
(заменяет один любой символ) и[]
(определяет диапазон возможных символов). Например:*.txt
- соответствует всем файлам с расширением .txt в текущей директории.docs/*.txt
- соответствует всем файлам с расширением .txt в папке docs, находящейся в текущей директории.**/*.txt
- соответствует всем файлам с расширением .txt в любой вложенной директории, начиная с текущей.
Давайте посмотрим на пример использования:
Задание file_tree
Напишите метод file_hierachy(path)
принимающий путь до директории. Выведите в консоль файлы в древовидной форме. Как это должно выглядеть в консоли:
Задание folder_size
Напишите метод calculate_folder_size(path)
, который принимает путь до директории и возвращает размер папки в гигабайтах, округленный до 2 символов после запятой
Рекоммендации:
Программы должна отлавливать все возможные ошибки (например, если передан несуществующий путь)
Last updated