Добавить строку в файл ruby

Обновлено: 04.07.2024

Ruby предоставляет полный набор методов ввода-вывода, реализованных в модуле Kernel. Все методы ввода / вывода являются производными от класса IO.

Класс IO предоставляет все основные методы, такие как чтение, запись, получение, ввод, readline, getc и printf .

В этой главе будут рассмотрены все основные функции ввода / вывода, доступные в Ruby. Для получения дополнительной информации, пожалуйста, обратитесь к Ruby Class IO .

Заявление пут

В предыдущих главах вы присвоили значения переменным, а затем распечатали выходные данные с помощью оператора put .

Оператор put указывает программе отображать значение, хранящееся в переменной. Это добавит новую строку в конце каждой строки, которую она пишет.

пример

Заявление получает

Оператор gets может использоваться для получения любого ввода от пользователя со стандартного экрана, называемого STDIN.

пример

Следующий код показывает, как использовать инструкцию gets. Этот код предложит пользователю ввести значение, которое будет сохранено в переменной val и, наконец, будет напечатано в STDOUT.

Заявление Putc

В отличие от оператора put , который выводит всю строку на экран, оператор putc может использоваться для вывода по одному символу за раз.

пример

Заявление о печати

Оператор print аналогичен оператору put . Единственное отличие состоит в том, что оператор put переходит на следующую строку после печати содержимого, тогда как в операторе print курсор располагается на той же строке.

пример

Открытие и закрытие файлов

До сих пор вы читали и писали на стандартный ввод и вывод. Теперь посмотрим, как играть с реальными файлами данных.

Метод File.new

Вы можете создать объект File, используя метод File.new для чтения, записи или того и другого, в соответствии со строкой режима. Наконец, вы можете использовать метод File.close, чтобы закрыть этот файл.

Синтаксис

Метод File.open

Вы можете использовать метод File.open, чтобы создать новый объект файла и назначить этот объект файла файлу. Однако есть одно различие между методами File.open и File.new . Разница в том, что метод File.open можно связать с блоком, тогда как вы не можете сделать то же самое с помощью метода File.new .

Режим чтения-записи. Указатель файла будет в начале файла.

Режим только для записи. Перезаписывает файл, если файл существует. Если файл не существует, создает новый файл для записи.

Режим чтения-записи. Перезаписывает существующий файл, если файл существует. Если файл не существует, создает новый файл для чтения и записи.

Режим только для записи. Указатель файла находится в конце файла, если файл существует. То есть файл находится в режиме добавления. Если файл не существует, он создает новый файл для записи.

Режим чтения и записи. Указатель файла находится в конце файла, если файл существует. Файл открывается в режиме добавления. Если файл не существует, он создает новый файл для чтения и записи.

Режим чтения-записи. Указатель файла будет в начале файла.

Режим только для записи. Перезаписывает файл, если файл существует. Если файл не существует, создает новый файл для записи.

Режим чтения-записи. Перезаписывает существующий файл, если файл существует. Если файл не существует, создает новый файл для чтения и записи.

Режим только для записи. Указатель файла находится в конце файла, если файл существует. То есть файл находится в режиме добавления. Если файл не существует, он создает новый файл для записи.

Режим чтения и записи. Указатель файла находится в конце файла, если файл существует. Файл открывается в режиме добавления. Если файл не существует, он создает новый файл для чтения и записи.

Чтение и запись файлов

Те же методы, которые мы использовали для «простого» ввода-вывода, доступны для всех файловых объектов. Итак, gets читает строку из стандартного ввода, а aFile.gets читает строку из объекта файла aFile.

Однако объекты ввода / вывода предоставляют дополнительный набор методов доступа, чтобы сделать нашу жизнь проще.

Метод sysread

Этот оператор выведет первые 20 символов файла. Указатель файла теперь будет размещен на 21-м символе в файле.

Метод syswrite

Это утверждение запишет «ABCDEF» в файл.

Метод each_byte

Символы передаются один за другим в переменную ch, а затем отображаются на экране следующим образом:

Метод IO.readlines

Класс File является подклассом класса IO. Класс IO также имеет несколько методов, которые можно использовать для манипулирования файлами.

В этом коде переменная arr является массивом. Каждая строка файла input.txt будет элементом массива arr. Следовательно, arr [0] будет содержать первую строку, а arr [1] будет содержать вторую строку файла.

Метод IO.foreach

Этот код будет построчно передавать содержимое файла теста в блок переменных, а затем вывод будет отображаться на экране.

Переименование и удаление файлов

Вы можете переименовывать и удалять файлы программно с помощью Ruby с помощью методов переименования и удаления .

Сегодня мы научимся писать данные в файлы, узнаем как работать со временем в Ruby, напишем программу-дневник.

План урока

  1. Как работать со временем в Ruby
  2. Запись в файлы, пишем дневник

Работаем со временем — класс Time

В Ruby есть класс для удобной работы со временем. Он называется Time . Например, чтобы понять, который сейчас час гики-программисты не смотрят на часы, а просто быстренько пишут программу на Ruby, в которой пишут одну строчку

Дело в том, что метод now (англ. «сейчас») класса Time возвращает текущий момент времени:

Любой экземпляр класса Time — объект «момента времени». Именно такой объект возвращает метод Time.now .

У экземпляра класса Time есть много полезных методов. Но самый важный из них — метод strftime , который возвращает время в виде строки по специальному шаблону, например

Выведет на экран текущее время в 24-часовом формате с точностью до минут:

Чтобы попросить метод strftime вывести время именно в таком формате, мы передаём ему в качестве параметра так называемый «формат времени», строчку "%H:%M" .

Вот эти вот конструкции %H и %M (специальные ключи) метод заменяет на соответствующие данные из объекта класса Time , у которого он был вызван.

  • %H — часы в 24-часовом формате
  • %M — минуты с нулём, если меньше 10

А остальные символы (всё, что не начинается с %, в нашем случае двоеточие), остаются как и были.

Чтобы вывести, например, текущую дату, нужно написать:

Это выведет что-то типа:

Это, кстати, не только в Ruby. Такой способ форматирования времени с помощью специальных шаблонов-строк — некий общепринятый в разных языках стандарт. Отличие может быть только в деталях, в названиях некоторых ключей.

О том, какие ещё бывают ключи в Ruby можно посмотреть по ссылке.

Добавление данных в файлы

Для того, чтобы записать что-то в файл, нам этот файл нужно сперва открыть, практически точно также, как мы это делали в 13-м уроке.

C той лишь разницей, что мы используем другой ключ: вместо "r:UTF-8" мы напишем "a:UTF-8" , потому что файл нам надо открыть для «добавления» (англ. append) строк.

Если такой файл есть, то всё, что мы запишем в файл, будет дописано в конец файла, если же такого файла ещё нет, то будет создан новый файл и всё, что мы запишем в него будет сохранено в этом новом файле.

Теперь давайте добавим что-нибудь в файл, это делается с помощью метода print у экземпляра класса File :

Обратите внимание на символы \n\r\ в конце — это символы переноса на следующую строку. Если мы что-то захотим писать в этот файл снова, всё, что мы будем дописывать, начнётся с новой строчки. Так просто красивее и удобнее.

Всегда заканчивайте ваши строки символом переноса строки \n ( \r добавляется для пользователей Windows). Ну и как обычно, закроем файл:

Всё, теперь в новом (если у вас ещё не было файла file.txt ) файле записана строка

Если мы повторно сделаем открытие файла с ключом "a:UTF-8" и проделаем всё заново, но запишем уже другую строку

То в файле будет записано уже две строки:

Итак, когда мы умеем создавать в наших программах новые файлы и дописывать текст в уже существующие, мы можем начать писать нашу программу-дневник.

Пишем программу «Дневник»

Для начала, как обычно, ставим задачу:

Написать программу, которая предлагает пользователю сделать дневниковую запись в консоли, ждёт, пока пользователь напишет текст, а потом сохраняет его, добавив текущее время, в файл с именем в виде текущей даты. Записи в разные дни кладутся в разные файлы, все записи одного и того же дня лежат в одном файле.

Дневник капитана

Задача, как видите, непростая! Но интересная. Приступаем.

Как обычно, создаём отдельную папку для нашей программы: c:\rubytut\lesson16 и в неё создаём файл my_diary.rb (не забудьте сохранить файл в кодировке UTF-8).

Начнём с того, что выведем на экран инструкцию для пользователя с помощью команды puts:

Обратите внимание — мы снова сохранили путь к программе в переменную current_path (как мы это делали в 13-м уроке).

Теперь давайте спросим у пользователя, что он хочет написать. Как обычно, делаем это с помощью команды STDIN.gets :

Мы будем записывать всё, что введёт пользователь в массив all_lines , пока пользователь не введёт end (по-английски маленькими буквами). После выполнения этого блока у нас в массиве all_lines вся нужная нам информация от пользователя (строчка all_lines.pop убирает из массива последний элемент, нам ведь не нужна там строчка с end ), осталось только записать её в файл. Новый файл, если это первая запись за сегодня и в уже существующий, если пользователь делает уже не первую запись за день.

Для этого мы заведём переменную time и запишем в неё текущее время

И с помощью метода strftime в переменную file_name мы запишем строку в формате «2014-11-25» (для удобства сортировки год выводим перед месяцем, а месяц перед днём, соединяем всё дефисами для наглядности):

а в переменную time_string запишем текущее время, как мы это делали в начале нашего урока:

Сделаем также строчку с разделителем, которую мы будем писать каждый раз в конце записи, чтобы отделять записи друг от друга внутри одного файла

Почти все готово. Осталось только записать в наш файл все строчки этого массива.

Мы будем это делать в цикле for . И на этот раз будем пользоваться не методом print , а методом puts , который также есть у каждого экземпляра класса File . Единственное отличие метода puts от метода print в том, что первый после записи в файл строчки, которую ему передали в параметрах, добавляет ещё перенос строки:

В файле file.txt будет две строки — первая с текстом «Строка с переносом» и вторая пустая. Итак, пора записать текст дневниковой записи в наш файл:

Обратите внимание, что путь к файлу мы как обычно собрали из нескольких частей:

  • переменной с текущей папкой программы current_path
  • слеша / , чтобы показать, что ищем и создаём файлы в этой папке
  • имени файла, которое храниться в переменной file_name
  • расширения файла .txt

Пора запускать программу:

Чтобы найти ваши записи, вам нужно в проводнике перейти в эту самую папку lesson16 .

Как только наиграетесь с программой, можете проверить, что она создаёт файлы для каждого нового дня, делает в них отметку о текущем времени и сохраняет то, что вы написали.

У меня есть файл конфигурации, к которому я хочу добавить строку, которая выглядит, например. например:

Новая строка не должна добавляться, а записываться где-то в середине файла. Поэтому я ищу конкретную позицию (или строку) в файле, и когда она была найдена, я вставляю новую строку:

Проблема заключается в том, что Ruby перезаписывает строку в этой позиции новым текстом, поэтому результат следующий:

То, что я хочу, является "реальной" вставкой:

Как это можно достичь?

Если это небольшой файл, я думаю, что самый простой способ:

  • Прочитайте полный файл.
  • Вставьте строку.
  • Запишите новый файл.

Вот как Rails делает это за кулисами.

Или вы можете скопировать его по строкам, а затем перезаписать оригинал с помощью mv следующим образом:

и если вы хотите добавить к существующему.

Пара других опций:

Самый простой способ - прочитать весь файл в памяти, затем записать первую часть в файл, записать вставленную строку в файл и записать оставшуюся часть в файл. Это должно быть относительно просто сделать, когда вы читаете файл в виде массива строк, но вы можете столкнуться с проблемами, если ваш файл очень велик, так как вы должны прочитать весь файл в памяти с помощью этого подхода.

В качестве альтернативы вы можете найти место, в которое хотите вставить строку, прочитать строки после этой точки в памяти, вернуться к этой точке в файле, записать новую строку в файл и, наконец, записать оставшиеся строки в файл. Снова вы столкнетесь с проблемами, если остальная часть файла будет очень большой, так как вы должны прочитать все это в памяти.

Третий подход - записать первую часть в новый файл, записать вставленную строку в новый файл, записать оставшуюся часть исходного файла в новый файл и, наконец, заменить старый файл на новый файл на файловая система. Этот подход позволяет вам работать с одной строкой за раз, чтобы вы могли обрабатывать файлы, которые не вписываются в память.

Причина, по которой это работает, заключается в том, что файл похож на массив с фиксированным размером байтов: когда вы пишете байт в файл, вы перезаписываете существующий байт (я игнорирую случай, когда вы добавляете к файл здесь). Таким образом, единственный способ вставить что-либо в файл - это перенести старый контент в новое место, прочитав его из старого местоположения и записав его в новое место. После этого вы можете "вставить" данные в свободную область.

Я хотел бы добавить одну строку в начало файла с Ruby, например:

Следующий код просто заменяет содержимое всего файла:

Это довольно распространенная задача:

Это фактический код:

Переименуйте старый файл во что-нибудь безопасное:

Покажи, что это работает:

Вы же не хотите пытаться полностью загрузить файл в память. Это будет работать до тех пор, пока вы не получите файл, размер которого превышает размер вашей ОЗУ, и машина не перейдет в режим сканирования или, что еще хуже, выйдет из строя.

Вместо этого прочтите его построчно. Чтение отдельных строк по-прежнему очень быстрое и масштабируемое. На вашем диске должно быть достаточно места для хранения оригинального и временного файлов.

Чисто, но работает. Минимизируйте операции, связанные с файлами.

Из командной строки вы можете:

Или более эффективно

К сожалению, оказывается, что параметры -i (на месте) на самом деле не на месте (и, в этом отношении, параметр sed не на месте) - мой файл будет иметь другой индекс после операции.

Это меня огорчило, потому что, по сути, я не могу фильтровать (добавлять) огромный файл, если у меня недостаточно места на диске для двух его копий.

Однако это не очень сложно сделать на месте (фильтрация в целом, а не только для первой строки). Все, что вам нужно сделать, это:

1) убедитесь, что у вас есть отдельные указатели для чтения и записи (или отдельные объекты File для чтения и записи) 2) убедитесь, что вы буферизовали непрочитанные части, которые вы собираетесь перезаписать 3) обрезать до файла в конце, если ваша операция фильтрации должен получиться более короткий файл

С его помощью вы можете делать

Или с исполняемым файлом:

Используйте осторожно (это может повредить ваш файл, если его прервать).

Вы можете попробовать это:

Не существует механизма, позволяющего легко делать то, что вы хотите.

Вместо этого вам нужно будет открыть файл, удалить файл, открыть новый файл под старым именем для записи, записать свое содержимое, а затем записать новый файл из содержимого старого файла. Звучит довольно запутанно, но код прост:

Обратите внимание, что механизм, который я использовал, не беспокоит проверку ошибок - вам, вероятно, следует обрабатывать ошибки в каждом запросе File.open() и запросе File.unlink() - и он предполагает, что все содержимое файла будет поместиться в памяти. Краткий пример:

Если вы хотите обрабатывать файлы, которые могут не умещаться полностью в памяти, вам следует закодировать такой цикл (непроверенный - лучше считать это псевдокодом):

В качестве альтернативы вы можете записать во временный файл, и если процесс записи завершится успешно, затем удалите файл и переименуйте временный файл на месте. Какой из подходов вам больше всего подходит.

Я придумал что-то вроде этого, это немного более наглядно и менее загадочно, чем другие решения, которые я видел:

И вы можете использовать это так:

Как говорили некоторые, вероятно, не используйте это для больших файлов, но это простое начало.

Читайте также: