Ruby: работа с ФС (файлами и папками)

ФАЙЛЫ

дока

Прежде всего нужно обозначить, что закрытие файла крайне необходимый процесс:
1) открытый файл может быть заблокирован файловой системой для других скриптов
2) при открытии создается file descriptor, их количество ограничено файловой системой, хотя и обычно значение ограничения довольно большое
3) могут произойти race conditions, когда несколько процессов пытаются прочитать/записать один и тот же ресурс (в данном случае файл) в один момент времени

Чтение и вывод

# вывод контента (первой строки)
File.open("test.txt") do |file| # открытие файла
 puts file.gets # вывод контента (первой строки)
end # автоматическое закрытие по завершению метода Open, про необходимость закрытия теория выше

# Вывод всех строк
File.open("test.txt").each do |line|
 puts line
end

# Кладем строки файла в array, где каждая новая строка является отдельным элементом массива. Этот метод не рекомендуется использовать если файл большой и нам не нужно сохранять все строки для последующей обработки, а нужно сохранить/изменить только ряд - в таком случае лучше использовать последовательное чтение без сохранения в массив, чтобы не выделять лишнюю память на большое количество данных.
array_of_lines = File.readlines("test.txt")

Аналогичный по функции пример, с созданием объекта в File class (проще использовать предыдущий метод):

file = File.new("test.txt") # открытие файла
puts file.gets # вывод контента (первой строки)
file.close # закрытие, про необходимость закрытия теория выше

Запись

Запись данных с перезаписью контента (w - write)
File.open("test.txt", "w") do |file|
  file.puts "I'm writing line"
end

Разбор строк:
1) File.open("test.txt", "w") do |file| # открытие файла в режиме записи ("w"), по умолчанию r, список всех возможностей тут (r, r+, w, w+, a, a+)
2) file.puts "I'm writing line" # ввод контента в файл (не последней строкой, а ПОЛНЫМ замещением текущих данных в файле), если файла не существует - он будет создан
3) end # автоматическое закрытие по завершению метода Open, про закрытие подробнее выше

Запись данных добивкой, без перезаписи контента (a - append)
File.open("test.txt", "a") do |file| 
  file.puts "I'm writing line" 
end 

Можно сократить до одной строки (полезно для debug)
File.open($log_file, 'a') { |f| f.puts "#{$cur_dt} --- EXCEPTION #{Time.now} mess #{mess} err #{err}" } if $debug == 1

Другие

полезные методы для работы с файлами

# Удаление файла
File.delete("file_name_to_delete")

# Удаление ряда файлов
files_to_delete = ["test1.txt", "test2.txt", "test3.txt"]
files_to_delete.each do |file|
 File.delete(file)
end

# Rename файла
File.rename("file_name_to_rename", "file_name_new")

# Проверка на существование файла
if File.exists?("test.txt")
 puts "File test.txt exist!"
end

# Получаем полный путь файла (по умолчанию директории из которой происходит запуск скрипта + имени файла) на основе относительного
puts File.expand_path("test.txt") 
/var/www/test.txt

# Получение имени без расширения и пути
puts File.basename("/var/www/test.txt", ".txt")
test

# Получение директории без имени файла
puts File.dirname("/var/www/test.txt") 
/var/www

# Получение атрибутов файла
File.size("test.txt") # размер файла в байтах
File.mtime("test.txt") # dt последней модификации

ПАПКИ

дока

# Показать текущий относительный путь, по умолчанию равен директории из которой происходит запуск скрипта
puts Dir.pwd
/home/user

# Изменение относительного пути - можно указать полный путь или будет изменение на текущий относительный + новый
puts Dir.pwd
dir.chdir("new_dir")
/home/user/new_dir

# Создаем новую директорию
Dir.mkdir("new_dir")

# Удаляем директорию, директория должна быть пустой (не иметь файлов или других директорий в ней)
Dir.delete("new_dir")

# Проверяем пустая ли директория
Dir.empty?("new_dir")

# Итерация по папке с получением имен файлов и директорий в заданной папке (., .. - в элементах это норма, это указатели текущей и корневой директорий). Во вложенных директориях файлы показаны не будут (не рекурсивно).
Dir.foreach("test_dir") do |entry|
 puts entry 
end

# Тоже самое что выше, но умеет работать рекурсивно и фильтровать выборку.
contents = Dir.glob("**/*") # ** - рекурсия, * - условия выборки aka wildcard (* - никаких, *.txt - только .txt)
contents.each do |entry|
puts entry 
end

# Получаем массив из имен файлов и директорий в заданной папке (., .. - в элементах это норма, это указатели текущей и корневой директорий)
Dir.entries("test_dir")

Leave a Reply