Чем в текстовом файле заканчивается каждая строка

Обновлено: 02.07.2024

Я предполагаю, что все здесь знакомы с пословицей, что все текстовые файлы должны заканчиваться новой строкой. Я знаю об этом "правиле" в течение многих лет, но я всегда задавался вопросом - почему?

ОТВЕТЫ

Ответ 1

3.206 Линия Последовательность из нуля или более символов non- <newline> плюс завершающий символ <newline>.

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

При работе с эмулятором терминала есть, по крайней мере, одно серьезное преимущество: все инструменты Unix ожидают этого соглашения и работают с ним. Например, при объединении файлов с помощью cat файл, оканчивающийся символом новой строки, будет иметь другой эффект, чем файл без:

И, как показано в предыдущем примере, при отображении файла в командной строке (например, через more ) файл с новой строкой в конце приводит к правильному отображению. Неправильно завершенный файл может быть искажен (вторая строка).

Для согласованности очень полезно следовать этому правилу - в противном случае потребуется дополнительная работа при работе со стандартными инструментами Unix.

Подумайте об этом по-другому: если строки не заканчиваются символом новой строки, сделать такие команды, как cat полезными, гораздо сложнее: как создать команду для объединения файлов таким образом, чтобы

  1. каждый файл начинается с новой строки, что вам нужно в 95% случаев; но
  2. это позволяет объединить последнюю и первую строку двух файлов, как в примере выше между b.txt и c.txt ?

Конечно, это решаемо, но вам нужно сделать использование cat более сложным (добавив позиционные аргументы командной строки, например, cat a.txt --no-newline b.txt c.txt ), а теперь команду, а не каждого отдельного человека. Файл управляет тем, как он вставляется вместе с другими файлами. Это почти наверняка не удобно.

. Или вам нужно ввести специальный символ стража, чтобы пометить строку, которая должна быть продолжена, а не завершена. Что ж, теперь вы застряли в той же ситуации, что и в POSIX, за исключением перевернутого (продолжение строки, а не символ завершения строки).

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

Ответ 2

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

GCC предупреждает об этом не потому, что не может обработать файл, а потому, что он должен быть частью стандарта.

Ответ 3

Этот ответ является попыткой технического ответа, а не мнения.

Если мы хотим быть пуристами POSIX, мы определяем строку как:

Последовательность из нуля или более символов non- <newline> плюс завершающий символ <newline>.

Неполная строка как:

Последовательность из одного или нескольких символов non- <newline> в конце файла.

Текстовый файл как:

Файл, содержащий символы, организованные в ноль или более строк. Строки не содержат символов NUL, и ни одна из них не может превышать длину байтов, включая символ <newline>. Хотя POSIX.1-2008 не делает различий между текстовыми файлами и двоичными файлами (см. Стандарт ISO C), многие утилиты производят только предсказуемый или значимый вывод при работе с текстовыми файлами. Стандартные утилиты, имеющие такие ограничения, всегда указывают "текстовые файлы" в своих разделах STDIN или INPUT FILES.

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

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

wc -l filename пример: wc -l filename .

С wc руководства мы читаем:

Строка определяется как строка символов, разделенных символом <newline>.

Каковы последствия для файлов JavaScript, HTML и CSS в том, что они являются текстовыми файлами?

В браузерах, современных IDE и других интерфейсных приложениях нет проблем с пропуском EOL в EOF. Приложения будут правильно анализировать файлы. Это связано с тем, что не все операционные системы соответствуют стандарту POSIX, поэтому для инструментов non- ОС (например, браузеров) было бы нецелесообразно обрабатывать файлы в соответствии со стандартом POSIX (или любым стандартом ОС -l).

В результате мы можем быть относительно уверены, что EOL в EOF практически не окажет негативного влияния на уровне приложений - независимо от того, работает ли он на ОС UNIX.

На данный момент мы можем с уверенностью сказать, что пропуск EOL в EOF безопасен при работе с JS, HTML, CSS на стороне клиента. На самом деле, мы можем констатировать, что минимизация любого из этих файлов, не содержащих <newline>, безопасна.

Мы можем сделать еще один шаг вперед и сказать, что в отношении NodeJS он также не может придерживаться стандарта POSIX, поскольку он может работать в non- POSIX-совместимых средах.

Что же нам тогда осталось? Инструменты системного уровня.

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

Тем не менее, не все оболочки будут автоматически придерживаться POSIX. Например, Bash не использует POSIX по умолчанию. Для этого есть переключатель: POSIXLY_CORRECT .

Оставаясь на пути к инструменту, для всех практических целей и задач, давайте рассмотрим это:

Пусть работает с файлом, который не имеет EOL. На момент написания статьи файл в этом примере представлял собой минимизированный JavaScript без EOL.

Обратите внимание, что размер файла cat является суммой отдельных его частей. Если конкатенация файлов JavaScript представляет собой проблему для файлов JS, более уместным было бы начинать каждый файл JavaScript с точки с запятой.

Как кто-то еще упомянул в этой теме: что если вы хотите cat два файла, вывод которых становится одной строкой вместо двух? Другими словами, cat делает то, что должна делать.

man cat упоминает только чтение ввода до EOF, а не <newline>. Обратите внимание, что переключатель -n команды cat также выводит строку с ограничением non- <newline> (или неполную строку) в виде строки, поскольку счет начинается с 1 (по словам man ).

-n Нумерация выходных строк, начиная с 1.

Теперь, когда мы понимаем, как POSIX определяет линию, это поведение становится неоднозначным или действительно совместимым с non-.

Понимание цели и соответствия заданному инструменту поможет определить, насколько важно завершить файлы EOL. В C, C++, Java (JAR) и т.д. некоторые стандарты будут предписывать новую строку для валидности - такого стандарта для JS, HTML, CSS не существует.

Например, вместо использования wc -l filename awk 'END< print x>' filename , и будьте уверены, что выполнение задачи не будет поставлено под угрозу файлом, который мы, возможно, захотим обработать, который мы сделали не писать (например, библиотеку третьей стороны, такие как уменьшенная JS мы curl г) - если наше намерение не было действительно считать строки в совместимом смысле POSIX.

Заключение

В реальных случаях будет очень мало случаев, когда пропуск EOL в EOF для определенных текстовых файлов, таких как JS, HTML и CSS, будет иметь негативное влияние - если вообще будет. Если мы полагаемся на присутствие <newline>, мы ограничиваем надежность наших инструментов только теми файлами, которые мы создаем, и открываем себя для потенциальных ошибок, допущенных сторонними файлами.

Мораль истории: Инженерные инструменты, у которых нет слабости полагаться на EOL в EOF.

Не стесняйтесь публиковать варианты использования, так как они относятся к JS, HTML и CSS, где мы можем изучить, как пропуск EOL отрицательно сказывается.

Ответ 4

Это может быть связано с разница между:

  • текстовый файл (каждая строка должна заканчиваться в конце строки)
  • (нет истинных "строк", о которых нужно говорить, и длина файла должна быть сохранена)

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

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

Несколько лет назад (2005) многие редакторы (ZDE, Eclipse, Scite. ) "забыли", что окончательный EOL, который не был очень ценится.
Не только это, но они неправильно интерпретировали этот окончательный EOL, так как "начали новую строку" и фактически начали отображать другую строку, как если бы она уже существовала.
Это было прекрасно видно с помощью "правильного" текстового файла с хорошо подобранным текстовым редактором, например, vim, по сравнению с открытием его в одном из вышеупомянутых редакторов. Он отобразил дополнительную строку под реальной последней строкой файла. Вы видите что-то вроде этого:

Ответ 5

Некоторые инструменты ожидают этого. Например, wc ожидает следующее:

Ответ 6

В основном существует много программ, которые не будут обрабатывать файлы правильно, если они не получат окончательный EOL EOF.

GCC предупреждает вас об этом, поскольку он ожидается как часть стандарта C. (см. раздел 5.1.1.2)

Ответ 7

Это происходит с самых первых дней использования простых терминалов. Новая строка char использовалась для запуска "сброса" переданных данных.

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

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

Ответ 8

В дополнение к приведенным выше практическим соображениям меня не удивило бы, если бы создатели Unix (Thompson, Ritchie и др.) или их предшественники Multics поняли, что существует теоретическая причина использовать ограничители строк, а не разделители строк: С терминаторами строк вы можете кодировать все возможные файлы строк. С разделителями строк нет никакой разницы между файлом нулевых строк и файлом, содержащим одну пустую строку; оба они закодированы как файл, содержащий нулевые символы.

Итак, причины таковы:

  • Потому что это определяет POSIX.
  • Потому что некоторые инструменты ожидают этого или "плохо себя ведут" без него. Например, wc -l не будет считать окончательную "строку", если она не заканчивается новой строкой.
  • Потому что это просто и удобно. В Unix cat работает, и он работает без осложнений. Он просто копирует байты каждого файла, без необходимости интерпретации. Я не думаю, что эквивалент DOS для cat . Использование copy a+b c приведет к объединению последней строки файла a с первой строкой файла b .
  • Поскольку файл (или поток) нулевых строк можно отличить от файла одной пустой строки.

Ответ 9

Также существует проблема с программированием с файлами, в которых нет новых строк: встроенный read Bash (я не знаю о других реализациях read ) работает не так, как ожидалось:

То есть, echo , если read не удалось из-за непустой строки в конце файла. Естественно, в этом случае на выходе будет еще одна новая строка, которая не была на входе.

Ответ 10

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

Ответ 11

Предположительно просто, чтобы какой-то код синтаксического анализа ожидал, что он будет там.

Я не уверен, что считаю это "правилом", и это, безусловно, не то, что я придерживаюсь религиозно. Наиболее разумный код будет знать, как разбор текста (включая кодировки) по очереди (любой выбор окончаний строк), с или без новой строки в последней строке.

В самом деле, если вы закончите с новой строкой: существует ли (теоретически) пустая конечная строка между EOL и EOF? Один, чтобы обдумать.

Ответ 12

Почему текстовые файлы заканчиваются символом новой строки?

Также выражается многими, потому что:

Многие программы не ведут себя хорошо, или без них.

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

Программы редко запрещают окончательный '\n' (я ничего не знаю).

Но это вызывает следующий вопрос:

Что должен делать код с текстовыми файлами без новой строки?

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

Если требуется конечный трейлинг '\n' , предупредите пользователя об его отсутствии и предпринятом действии. IOW, проверьте формат файла. Примечание. Это может включать ограничение на максимальную длину строки, кодировку символов и т.д.

Четко определить документ, обработать код отсутствующего окончательного '\n' .

Невозможно создать файл, в котором отсутствует окончание '\n' .

Ответ 13

Я сам это задавался годами. Но сегодня я столкнулся с серьезной причиной.

Представьте файл с записью на каждой строке (например: файл CSV). И что компьютер записывал записи в конце файла. Но он внезапно упал. Джи была последней строкой? (не хорошая ситуация)

Но если мы всегда завершаем последнюю строку, тогда мы бы знали (просто проверьте, завершена ли последняя строка). В противном случае нам, вероятно, придется каждый раз отбрасывать последнюю строку, чтобы быть в безопасности.

Ответ 14

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

Ответ 15

Здесь очень поздно, но я столкнулся с одной ошибкой в обработке файлов, которая произошла из-за того, что файлы не заканчивались пустым переводом строки. Мы обрабатывали текстовые файлы с помощью sed и sed опускал последнюю строку в выводе, что приводило к неправильной структуре json и отправляло остальную часть процесса в состояние сбоя.

Все, что мы делали, было:

Есть один пример файла: foo.txt с некоторым содержанием json внутри.

Файл был создан на машине вдов, и оконные скрипты обрабатывали этот файл с помощью команд powershall. Все хорошо.

Когда мы обработали тот же файл, используя sed в командной sed 's|value|newValue|g' foo.txt > foo.txt.tmp в sed 's|value|newValue|g' foo.txt > foo.txt.tmp Вновь созданный файл был

и бум, он отказал остальным процессам из-за недопустимого JSON.

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

Ответ 16

Представьте, что файл обрабатывается, пока файл все еще создается другим процессом.

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

Ответ 17

Мне лично нравятся новые строки в конце файлов исходного кода.

Возможно, это связано с Linux или всеми UNIX-системами. Я помню там ошибки компиляции (gcc, если я не ошибаюсь), потому что файлы исходного кода не заканчивались пустой пустой строкой. Почему это было сделано так, что вам интересно.

Ответ 18

ИМХО, это вопрос личного стиля и мнения.

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

Позже я поместил эту новую строку, чтобы было легче выбрать финальную строку с помощью shift + downarrow.

Иногда при просмотре диффов коммитов через git log или git diff можно заметить следующий вывод:

Или на GitHub в интерфейсе для просмотра диффов:

GitHub "now newline at end of file" warning

Почему это так важно, что Git и GitHub предупреждают нас об этом? Давайте разберемся.

Что может быть проще, чем текстовый файл? Просто текстовые данные — как хранятся на диске, так и отображаются. На самом деле правительство нам врёт всё немного сложнее.

Оффтопик про управляющие символы ASCII

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

  • нулевой символ ( x00 , \0 ) — часто используется для кодирования конца строки в памяти; т.е. программа считывает символы из памяти по одному до тех пор, пока не встретит нулевой символ, и тогда строка считается завершённой;
  • табуляция ( \x09 , \t ) — используется для выравнивания данных по границе столбца, так что это выглядит как таблица;
  • перевод строки ( \x0a , \n ) — используется для разделения текстовых данных на отдельные строки;
  • возврат каретки ( \x0d , \r ) — переместить курсор в начало строки;
  • возврат на один символ ( \x08 , \b ) — переместить курсор на один символ назад;
  • звонок ( \x07 , \a ) — если набрать этот символ в терминале, то будет бибикающий символ; именно так консольные программы, типа vim , бибикают на пользователей; .

Многие эти символы пришли к нам из эпохи печатных машинок, поэтому у них такие странные названия. И действительно, в контексте печатной машинки или принтера такие операции, как перевод строки (сместить лист бумаги вверх так, чтобы печатающая головка попала на следующую строку), возврат каретки (переместить печатающую головку в крайнее левое положение) и возврат на один символ назад, обретают смысл. При помощи возврата на один символ назад создавались жирные символы (печатаешь символ, возвращаешься назад и печатаешь его ещё раз) и буквы с диакритическими знаками, такие как à или ã (печатаешь символ, возвращаешься назад и печатаешь апостроф или тильду). Но зачем печатной машинке бибикалка?

Сегодня многие из этих символов потеряли смысл, но некоторые до сих пор выполняют функцию, схожую с исходной.

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

Для набора символа переноса строки достаточно нажать клавишу "Enter", но на разных платформах этот символ закодируется по-разному:

  • в Unix-совместимых системах (включая современные версии macOS) используется один символ перевода строки ( LF );
  • в Windows используется сразу два символа — возврат каретки ( CR ) и перевод строки ( LF );
  • в очень старых версиях Mac OS (до 2001 года) использовался один символ CR .

Как видите, Windows точнее всего эмулирует поведение печатной машинки.

В языках программирования символ новой строки часто кодируют при помощи бэкслэш-последовательностей, таких как \n или \r\n . Нужно понимать разницу между такой последовательностью и настоящим символом переноса строки. Если в редакторе в файле *.txt просто набрать \n и сохранить, то вы получите ровно то, что написали. Символом переноса строки оно не станет. Нужно что-то, что заменит эти бэкслэш-последовательности на настоящие символы переноса строки (например, компилятор или интерпретатор языка программирования).

Согласно определению из стандарта POSIX, который тоже пришёл к нам из эпохи печатных машинок:

Строка — это последовательность из нуля или более символов, не являющихся символом новой строки, и терминирующего символа новой строки.

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

Т.е. если вы не ставите символ переноса строки в конце строки, то формально по стандарту такая строка не является валидной. Множество утилит из Unix, которыми я пользуюсь каждый день, написано в согласии с этим стандартом, и они просто не могут правильно обрабатывать такие "сломанные" строки.

Давайте, например, через Python создадим такой файл со сломанными строками:

Сколько по-вашему в этом файле строк? Три? Давайте посмотрим, что об этом файле думает утилита wc , которая с флагом -l умеет считать количество строк в файле:

Упс! wc нашла только 2 строки!

Давайте создадим еще один файл:

И попробуем теперь склеить два созданных файла при помощи утилиты cat :

Название cat — это сокращение от "конкатенация", и никак не связано с котиками. А жаль.

И опять какой-то странный результат! В большинстве случаев это не то, чего вы бы ожидали, но вполне возможны ситуации, когда вам нужен именно такой результат. Именно поэтому утилита cat не может самостоятельно вставлять отсутствующие символы переноса строки, иначе это сделало бы её поведение неконсистентным.

Это только пара примеров, но многие другие утилиты, которые работают с текстом (например, diff , grep , sed ), имеют такие же проблемы. Собственно говоря, это даже не проблемы, а их задокументированное поведение.

Ещё доводы:

Самый простой способ перестать думать о пустых строках и начать жить — это настроить свой текстовый редактор или IDE на автоматическое добавление символа переноса строки в конец файлов:

  • PyCharm и другие IDE JetBrains: Settings > Editor > General > Ensure an empty line at the end of a file on Save ;
  • VS Code: "files.insertFinalNewline": true .

Для других редакторов смотрите настройку здесь.

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

В текстовом редакторе это выглядит как лишняя пустая строка в конце файла:

Я предполагаю, что все здесь знакомы с пословицей, что все текстовые файлы должны заканчиваться новой строкой. Я знал об этом «правиле» много лет, но всегда задавался вопросом - почему?

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

GCC предупреждает об этом не потому, что он не может обработать файл, а потому, что он должен как часть стандарта.

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

Если мы хотим быть сторонниками POSIX, мы определяем строку как:

Последовательность из нуля или более символов, отличных от , плюс завершающий символ .

Неполная строка как:

Последовательность из одного или нескольких символов, отличных от , в конце файла.

Текстовый файл как:

Файл, содержащий символы, сгруппированные в ноль или более строк. Строки не содержат символов NUL, и длина ни одной из них не может превышать байтов, включая символ . Хотя POSIX.1-2008 не делает различий между текстовыми файлами и двоичными файлами (см. Стандарт ISO C), многие утилиты выдают предсказуемый или осмысленный вывод только при работе с текстовыми файлами. Стандартные утилиты с такими ограничениями всегда указывают «текстовые файлы» в своих разделах STDIN или INPUT FILES.

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

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

Показательный пример: wc -l filename .

Из руководства wc мы читаем:

Строка определяется как строка символов, разделенных символом .

Каковы последствия того, что файлы JavaScript, HTML и CSS являются текстовыми файлами?

В браузерах, современных IDE и других интерфейсных приложениях нет проблем с пропуском EOL при EOF. Приложения правильно проанализируют файлы. Это необходимо, поскольку не все операционные системы соответствуют стандарту POSIX, поэтому для инструментов, не относящихся к ОС (например, браузеров), было бы непрактично обрабатывать файлы в соответствии со стандартом POSIX (или любым стандартом уровня ОС).

В результате мы можем быть относительно уверены, что EOL в EOF практически не окажет отрицательного воздействия на уровне приложения - независимо от того, работает ли оно в ОС UNIX.

На данный момент мы можем с уверенностью сказать, что пропуск EOL в EOF безопасен при работе с JS, HTML, CSS на стороне клиента. Фактически, мы можем заявить, что минимизация любого из этих файлов, не содержащих , является безопасной.

Мы можем сделать еще один шаг и сказать, что что касается NodeJS, он тоже не может придерживаться стандарта POSIX, так как он может работать в средах, несовместимых с POSIX.

С чем мы тогда остались? Инструменты системного уровня.

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

Даже в этом случае не все оболочки автоматически соответствуют POSIX. Например, Bash по умолчанию не соответствует POSIX. Для его включения есть переключатель: POSIXLY_CORRECT .

Оставаясь на пути к инструментарию, для всех практических намерений и целей давайте рассмотрим следующее:

Давайте работать с файлом без EOL. На момент написания файл в этом примере представляет собой миниатюрный JavaScript без EOL.

Обратите внимание, что размер файла cat - это в точности сумма его отдельных частей. Если конкатенация файлов JavaScript является проблемой для файлов JS, более уместно будет начинать каждый файл JavaScript с точки с запятой.

Как кто-то еще упомянул в этой ветке: что, если вы хотите cat два файла, вывод которых становится одной строкой вместо двух? Другими словами, cat делает то, что должен делать.

В man из cat упоминается только чтение ввода до EOF, но не . Обратите внимание, что переключатель -n в cat также распечатает строку без завершения (или неполную строку ) как строку - поскольку счет начинается с 1 (согласно man .)

-n Нумеровать выходные строки, начиная с 1.

Теперь, когда мы понимаем, как POSIX определяет строку , это поведение становится неоднозначным или действительно несовместимым.

Понимание цели и соответствия данного инструмента поможет определить, насколько критично завершать файлы с помощью EOL. В C, C ++, Java (JAR) и т. Д. Некоторые стандарты диктуют новую строку для действительности - такого стандарта не существует для JS, HTML, CSS.

Например, вместо использования wc -l filename можно было бы использовать awk 'END< print x>' filename , и будьте уверены, что успех задачи не будет поставлен под угрозу из-за файла, который мы, возможно, захотим обработать, который мы не писали (например, сторонняя библиотека, такая в качестве минифицированного JS мы curl d) - если мы действительно не намеревались подсчитать строки в соответствии с POSIX.

Заключение

Будет очень мало реальных случаев использования, когда пропуск EOL в EOF для определенных текстовых файлов, таких как JS, HTML и CSS, окажет негативное влияние - если вообще повлияет. Если мы полагаемся на присутствие , мы ограничиваем надежность наших инструментов только файлами, которые мы создаем, и открываем себя для потенциальных ошибок, вносимых сторонними файлами.

Мораль истории: инструменты инженера, которые не имеют недостатков, связанных с EOL в EOF.

Не стесняйтесь публиковать варианты использования, поскольку они применяются к JS, HTML и CSS, где мы можем изучить, как пропуск EOL имеет неблагоприятный эффект.

Это может быть связано с разницей между:

  • текстовый файл (каждая строка должна заканчиваться концом строки)
  • двоичный файл (здесь нет настоящих "строк", и длина файла должна быть сохранена)

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

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

Несколько лет назад (2005 г.) многие редакторы (ZDE, Eclipse, Scite, . ) «забыли» этот последний EOL, , что не очень понравилось .
Более того, они неправильно интерпретировали этот последний EOL как «начало новой строки» и фактически начали отображать другую строку, как если бы она уже существовала.
Это было очень заметно с «правильным» текстовым файлом с хорошо настроенным текстовым редактором, таким как vim, по сравнению с открытием его в одном из вышеперечисленных редакторов. Он отображал дополнительную строку под реальной последней строкой файла. Вы видите что-то вроде этого:

Некоторые инструменты этого ожидают. Например, wc ожидает этого:

В основном есть много программ, которые не будут правильно обрабатывать файлы, если они не получат окончательный EOL EOF.

GCC предупреждает вас об этом, потому что это ожидается как часть стандарта C. (очевидно, раздел 5.1.1.2)

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

Я сам размышлял об этом много лет. Но сегодня я нашел серьезную причину.

Представьте себе файл с записью в каждой строке (например, файл CSV). И что компьютер записывал записи в конец файла. Но он внезапно разбился. Ну и дела, последняя строчка была завершена? (не очень хорошая ситуация)

Но если бы мы всегда завершали последнюю строку, тогда мы бы знали (просто проверьте, завершена ли последняя строка). В противном случае нам, вероятно, придется каждый раз отбрасывать последнюю строку на всякий случай.

Это происходит с самых первых дней, когда использовались простые терминалы. Символ новой строки использовался для запуска «сброса» переданных данных.

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

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

В дополнение к вышеупомянутым практическим причинам меня не удивило бы, если бы создатели Unix (Томпсон, Ритчи и др.) Или их предшественники Multics осознали, что существует теоретическая причина использовать терминаторы строки, а не разделители строк: терминаторами, вы можете закодировать все возможные файлы строк. С разделителями строк нет разницы между файлом с нулевыми строками и файлом, содержащим одну пустую строку; оба они закодированы как файл, содержащий нулевые символы.

  1. Потому что это то, как это определяет POSIX.
  2. Потому что некоторые инструменты ожидают этого или «плохо себя ведут» без него. Например, wc -l не будет считать последнюю «строку», если она не заканчивается новой строкой.
  3. Потому что это просто и удобно. В Unix cat просто работает и работает без каких-либо осложнений. Он просто копирует байты каждого файла без какой-либо интерпретации. Я не думаю, что есть DOS-эквивалент cat . Использование copy a+b c приведет к объединению последней строки файла a с первой строкой файла b .
  4. Потому что файл (или поток) из нулевых строк можно отличить от файла из одной пустой строки.

Также существует практическая проблема программирования с файлами без символов новой строки в конце: встроенный read Bash (я не знаю о других реализациях read ) не работает должным образом:

То есть выполните echo , если read не удалось из-за непустой строки в конце файла. Естественно, в этом случае в выводе будет одна дополнительная новая строка, которой не было во вводе.

По-видимому, просто потому, что какой-то код синтаксического анализа ожидал, что это будет.

Я не уверен, что считаю это «правилом», и уж точно не то, чего я придерживаюсь религиозно. Наиболее разумный код будет знать, как анализировать текст (включая кодировки) построчно (любой выбор окончания строки) с символом новой строки в последней строке или без него.

В самом деле - если вы заканчиваете новой строкой: есть ли (теоретически) пустая последняя строка между EOL и EOF? Надо задуматься .

Почему (текстовые) файлы должны заканчиваться новой строкой?

Как это хорошо выражается многими, потому что:

Многие программы плохо себя ведут или не работают без этого.

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

Программы редко запрещают final '\n' (я не знаю ни одного).

Однако возникает следующий вопрос:

Что должен делать код с текстовыми файлами без новой строки?

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

Если последний завершающий '\n' необходим, предупредите пользователя о его отсутствии и о предпринятых действиях. IOWs, проверьте формат файла. Примечание. Это может включать ограничение максимальной длины строки, кодировки символов и т. Д.

Четко опишите, документируйте, как код обрабатывает отсутствующий окончательный '\n' .

По возможности не генерируйте файл без окончания '\n' .

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

Все, что мы делали, это:

Есть один пример файла: foo.txt с некоторым содержанием json внутри него.

Файл был создан на машине Windows, и скрипты окна обрабатывали этот файл с помощью команд PowerShell. Все хорошо.

Когда мы обработали тот же файл с помощью команды sed sed 's|value|newValue|g' foo.txt > foo.txt.tmp

Вновь созданный файл был

И бум, он отказал остальным процессам из-за недопустимого JSON.

Так что всегда рекомендуется заканчивать файл пустой новой строкой.

У меня всегда было впечатление, что это правило пришло из тех времен, когда анализировать файл без символа новой строки в конце было сложно. То есть вы закончите писать код, в котором конец строки определяется символом EOL или EOF. Было проще предположить, что линия заканчивается EOL.

Почему текстовые файлы должны заканчиваться новой строкой?

Возьмите файл со следующим содержанием,

Где \n означает символ новой строки, которым в Windows является \r\n , символ возврата, за которым следует перевод строки, потому что это так круто, не так ли?

Сколько строк в этом файле? Windows говорит 3, мы говорим 3, POSIX (Linux) говорит, что файл поврежден, потому что в конце должен быть \n .

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

А какая у него вторая строка? О, вот и первое сильное разделение :

  • Windows говорит two , потому что файл состоит из «строк, разделенных символами новой строки» (wth?);
  • POSIX говорит two\n , добавляя, что это настоящая, честная фраза.

В чем же тогда последствия выбора Windows? Простой:

Нельзя сказать, что файл состоит из строк

Почему? Попробуйте взять последнюю строчку из предыдущего файла и повторить ее несколько раз . Что у вас получится? Этот:

Вместо этого попробуйте поменять местами вторую и третью строку . И вы получите следующее:

Вы должны сказать, что текстовый файл представляет собой чередование строк и \n , которое начинается строкой и заканчивается строкой

Что довольно сложно, не так ли?

И вы хотите еще одного странного следствия?

Вы должны согласиться с тем, что пустой файл (0 бит) - это однострочный файл, волшебным образом, всегда, потому что они крутые в Microsoft

Это настоящее безумие, вам не кажется?

Каковы последствия выбора POSIX?

Быть серьезным

В предыдущем тексте я провокационный по той причине, что работа с текстовыми файлами без символа \n в конце вынуждает вас обращаться с ними с помощью специальных тиков / хаков. Вам всегда нужен if / else где-нибудь, чтобы все работало, где ветвь, имеющая дело с поврежденной линией, имеет дело только с поврежденной линией, а все другие линии занимают другую ветвь. Это немного расистски, не так ли?

Мой вывод

Я поддерживаю определение строки в POSIX по следующим причинам:

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

Представьте, что файл обрабатывается, а файл все еще создается другим процессом.

Это может быть связано с этим? Флаг, указывающий, что файл готов к обработке.

Мне лично нравятся новые строки в конце файлов исходного кода.

Это может быть связано с Linux или всеми системами UNIX, если на то пошло. Я помню там ошибки компиляции (gcc, если я не ошибаюсь), потому что файлы исходного кода не заканчивались пустой новой строкой. Остается задаться вопросом, почему это было сделано именно так.

ИМХО, это вопрос личного стиля и мнения.

Раньше я не ставил эту новую строку. Сохраненный символ означает большую скорость через модем 14,4K.

Позже я поставил эту новую строку, чтобы было легче выбрать последнюю строку с помощью shift + downarrow.

Для связи файла в коде программы и действительного файла на внешнем носителе используется процедура ASSIGN :

Текстовые файлы в паскале: процедуры работы

Возможные расширения файлов:
*.txt, *.log,
*.htm, *.html

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

Предусмотрены два режима работы: режим для записи в файл информации и для чтения ее из файла. Одновременная запись и чтение запрещены.

Открытие файла

Допустим, мы в программе описали переменную для работы с текстовым файлом:

Рассмотрим дальнейшую последовательность работы с ним, и рассмотрим процедуры, необходимые для работы с текстовым файлом в Паскале:

процедура открытия существующего файла для чтения при последовательном доступе:

процедура открытия создаваемого файла для записи в него информации; если файл с таким именем уже существует, то информация в нем стирается:

процедура добавления в конец:

  • При открытии курсор устанавливается в начало файла.

открытие файла

Чтение из файла

Read (f, список переменных); ReadLn (f, список переменных);

Отличие ReadLn от Read в том, что при использовании readln после прочтения данных пропускаются все оставшиеся символы в данной строке, включая метку конца строки.

  • чтение осуществляется с той позиции, где в данный момент стоит курсор;
  • после чтения курсор сдвигается к первому непрочитанному символу.

Чтение до конца строки

close ( f ); reset ( f );

Запись в текстовый файл

Write (f, список переменных); WriteLn (f, список переменных);

Процедуры работы с файлом и закрытие файла

Нахождение конца файла:

Логическая функция, возвращающая True, если достигнут конец файла.

Нахождение конца строки:

Логическая функция, возвращающая True, если достигнут конец строки.

Удалить файл в Паскале

Переименование файла в Паскале

rename(переменная_файла,'новое имя файла');

Закрытие:

Важно: Таким образом, работа с файлом осуществляется через три основных шага:

Рассмотрим пример работы с файлами в паскале:

Пример 1: В файле text.txt записаны строки. Вывести первую и третью из них на экран.
(предварительно создать text.txt с тремя строками)

var filetext: text; a,b,c:string; begin assign(filetext,'c:\text.txt'); reset(filetext); readln(filetext,a); readln(filetext,b); readln(filetext,c); close(filetext); writeln(a); writeln(c); end.

Пример 2: Дан текстовый файл. Вывести количество содержащихся в нем символов и строк (маркеры концов строк EOLN и конца файла EOF при подсчете количества символов не учитывать).

* Из задачника М. Э. Абрамян (Text4)

var F: Text; N,K:integer; Name:String; C:Char; begin Assign(F,'c:\text.txt'); Reset(F); N:=0; K:=0; While not eof(F) do begin inc(N); While not eoln(f) do begin inc(K); Read(F,C); end; Readln(F); end; Close(F); Writeln(N,' ',K); end.

Пример 3:
Считать из файла input.txt числа (числа записаны в столбик). Затем записать их произведение в файл output.txt

var p, x: integer; f: text; begin assign(f, 'input.txt'); reset(f); p := 1; while not eof(f) do begin readln(f, x); p := p * x; end; close(f); assign(f, 'output.txt'); rewrite(f); writeln(f, 'Произведение чисел ', p); close(f); end.

var filetext: text; a:string; i:integer; begin assign(filetext,'c:\text.txt'); rewrite(filetext); for i:=1 to 10 do . reset(filetext); for i:=1 to 10 do begin . . end; close(filetext); end.

pascal file text2. Даны целые положительные числа N и K. Создать текстовый файл и записать в него N строк, каждая из которых состоит из K символов «*» (звездочка).

* Из задачника М. Э. Абрамян (Text1)

pascal file text3. Дана строка S и текстовый файл. Добавить строку S в конец файла.

* Из задачника М. Э. Абрамян (Text5)

Пример 4: Дана строка S и текстовый файл. Добавить строку S в начало файла.

* Из задачника М. Э. Абрамян (Text7)

var F_in,F_out: Text; Name,S: String; begin Write('S: '); Readln(S); Assign(F_in,'c:\text.txt'); Reset(F_in); Assign(F_out,'c:\text1.txt'); Rewrite(F_out); Writeln(F_out,S); While not eof(F_in) do begin Readln(F_in,S); Writeln(F_out,S); end; Close(F_in); Close(F_out); Erase(F_in); Rename(F_out,'c:\text.txt'); end.

pascal file text4. Дано целое число K и текстовый файл. В данном файле вставить пустую строку перед строкой с номером K . Если строки с таким номером нет, то оставить файл без изменений.
Для решения задачи можно использовать дополнительный временный файл.

* Из задачника М. Э. Абрамян (Text9)

Пример 5: Дано целое число K и текстовый файл. Удалить из файла строку с номером K . Если строки с таким номером нет, то оставить файл без изменений.

* Из задачника М. Э. Абрамян (Text15)

var F_in,F_out: Text; Name,line: string; K,i:integer; begin Write('K: '); Readln(K); Assign(F_in,'c:\text.txt'); Assign(F_out,'c:\text1.txt'); Reset(F_in); Rewrite(F_out); i:=0; While not eof(F_in) do begin Readln(F_in,line); inc(i); if i<>K then Writeln(F_out,line); end; Close(F_in); Close(F_out); Erase(F_in); Rename(F_out,'c:\text.txt'); end.

Пример 6: Дан текстовый файл F1 с набором нулей и единиц. Необходимо заменить все вхождения сочетаний 101 на 000 . Скорректированные записи поместить в файл F2 .

var f1,f2: text; pole:string; pz:integer; begin assign(f1,'1.txt'); assign(f2,'2.txt'); reset(f1); rewrite(f2); while not eof(f1) do begin readln(f1, pole); while pos('101',pole)<>0 do begin pz:=pos('101',pole); delete(pole,pz,3); insert('000',pole,pz); end; writeln(f2,pole) end; close(f1); close(f2); end.

Работа с данными из файла как с массивом

  • для сортировки необходим массив, для того чтобы одновременно работать со всеми числами;
  • неизвестно общее количество чисел.
  • объявляем массив для 100 элементов;
  • открываем файл на чтение, просчитываем количество чисел, заполняя массив, сохраняем количество в N;
  • сортируем N элементов массива;
  • записываем результат в файл.
pascal file text6. Дан текстовый файл. Удалить из него все пустые строки.

* Из задачника М. Э. Абрамян (Text16)

А теперь вернемся к олимпиадному заданию по Паскалю, частично решенному на одном из предыдущих заданиях:

p.in p.out
3
hello earth
khoor hduwk

var a:char; i,n,k:byte; s,s1:string; f_in,f_out:text; begin Assign(F_in,'z:\p.in'); Assign(F_out,'z:\p.out'); Reset(F_in); Rewrite(F_out); s1:=''; readln(f_in,k); readln(f_in,s); for i:=1 to length(s) do begin n:=ord(s[i]); if n<>32 then n:=n+3; if . then . ; if . then . ; if . then . ; a:=chr(. ); s1:=. ; end; writeln(s1); writeln(f_out,s1); close(f_in); close(f_out) end.

var a:char; i,n,k:byte; s,s1:string; f_in,f_out:text; begin Assign(F_in,'z:\p.in'); Assign(F_out,'z:\p.out'); Reset(F_in); Rewrite(F_out); s1:=''; readln(f_in,k); readln(f_in,s); for i:=1 to length(s) do begin n:=ord(. ); if n<>32 then n:=n+3; if n=123 then n:=97; if n=124 then n:=98; if n=125 then n:=99; a:=chr(n); s1:=s1+a; end; writeln(s1); writeln(f_out,s1); close(f_in); close(f_out) end.

полное решение var s, s1: string; i, j, a, n, k, b: integer; begin n := 97; s1 := ''; readln(s); readln(k); for i := 1 to length(s) do begin if s[i] <> ' ' then begin a := ord(s[i]); if a > 122 - k then for j :=123 - k to 122 do begin b:=122-j; if a = j then begin a := n+k-b-1; inc(n); end; end else a := a + k; s1 := s1 + chr(a) end else s1 := s1 + ' ' end; writeln(s1)end. --> pascal file text7. Пять делителей.
Имя входного файла: z3.in
Имя выходного файла: z3.out

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