|
| |||||||||||||||||||||||
Паскаль для новичков (часть 29)Текстовые файлыАвтор: Владислав Демьянишин
![]() var FileText : text;
Учитывая нестройность структуры текстовых файлов, строгое позиционирование на определённую строку такого файла, посредством процедуры Seek, становится невозможным. А так как организация ввода-вывода в такой файл является строго последовательной, то есть строка за строкой, то для такого файла нельзя одновременно выполнять операции чтения и записи. Исходя из этого, выше описанные операции приобретают несколько иной функциональный смысл в отношении к текстовым файлам:
– Смысл процедуры Assign остаётся прежним, она выполняет связывание файловой переменной с файлом.
– Операция Reset открывает текстовый файл для последовательного чтения и позиционирует указатель файла на первую строку.
– Операция Rewrite открывает текстовый файл для последовательной модификации, очищает его и позиционирует указатель на начало файла.
– Операция Close имеет прежний смысл.
– Операция записи Write при выводе переменной целого или вещественного типа преобразуют численное значение в текстовый вид, например, 1234 = “1234”. Таким образом, данная процедура пишет текст в текущую строку файла. Процедура WriteLn записывает текст в текущую строку и завершает её кодом “конец строки”, после чего дальнейший вывод будет осуществляться уже в новую строку пока не будет выведен очередной код “конец строки”. Синтаксис обоих процедур допускает вывод в строку одновременно значений целого списка переменных.
– Процедура Read позволяет читать текст из позиции текущей строки файла, при этом будет прочитана вся строка, а следующий вызов Read будет возвращать пустую строку, что будет означать что достигнут конец строки. Поэтому, чтобы не было таких холостых прогонов можно использовать процедуру ReadLn, которая читает строку и переводит указатель на следующую строку файла. Следует учесть, что если в качестве параметра данной процедуры стоит переменная численного типа, то фрагмент прочитанной строки будет интерпретироваться как символьное представление числа, поэтому при записи таких фрагментов в файл, их следует отделять от дальнейшей текстовой информации пробелом или символом табуляции, иначе есть риск возникновения ошибки при преобразовании набора символов алфавита в численное значение.
– Для обнаружения того, что конец строки достигнут, следует вызывать функцию EoLn(var F:Text):boolean результат True которой красноречиво даст знать о исчерпании текущей строки. Для перехода на начало следующей строки, можно вызвать ReadLn с единственным параметром – файловой переменной.
– Смысл функции EoF прежний.
Среди специальных операций над текстовыми файлами имеются следующие:
– Операция открытия текстового файла для добавления строк в хвост файла Append(var F:Text) не очищает файл, а позиционирует указатель на конец файла, после чего операции вывода будут добавлять строки в хвост файла.
– Процедура SetTextBuf(var F:Text; var Buf [; Size:word]) подготавливает альтернативный буфер обмена для текстового файла, который будет открыт. При этом следует указать буфер Buf, которым может быть массив и его размер Size. Можно конечно обойтись без данной процедуры, так как система автоматически при открытии файла выделяет буфер обмена величиной 128 байт. Данная процедура полезна, если необходимо ускорить процесс обмена данными с текстовым файлом. Если не указать параметр Size, то размер указанного буфера Buf будет считаться равным 128 байтам.
Секрет оператора WriteЕсли заглянуть в систему помощи текстового редактора Turbo Pascal, то можно увидеть следующий формат оператора Write[Ln]:
Write( [ var F : Text; ] V1 [, V2,.., Vn ] )
где V1 – переменная или константа, которая может быть единственным параметром, а может быть целый список переменных и/или констант, перечисленных через запятую V1, V2, .., Vn различных типов, таких как стандартные скалярные и ограниченные. Такой оператор выводит значения переменных на экран. При этом, если указана одна переменная, то её значение преобразуется в строку и выводится на экран. Если указан целый список переменных, то значение каждой переменной в отдельности преобразуется в отдельное строчное значение и затем все эти строчные значения конкатенируются, то есть складываются в единую строку.
Если указан параметр F (самым первым), которым может быть, например, файловая переменная типа Text, то вывод значений будет осуществляться в открытый текстовый файл аналогичным образом в виде текста. К сожалению, данное описание является не полным, так как оператор Write[Ln] наделён дополнительным свойством форматировать текстовое представление целых и вещественных значений перечисленных параметров в соответствии со следующим описанием:
Write( V1 [: width [: decimals>, V2 [: width [: decimals>, .., Vn [: width [: decimals> )
где V1, V2,..,Vn – догадайтесь сами; Width – параметр может отсутствовать, и может быть переменной или константой, указанной через двоеточие, и определяющей минимальную длину строки, представляющей выводимое значение; Decimals – параметр может отсутствовать, а если присутствует, то только с указанием после присутствующего параметра Width через двоеточие, и также может быть переменной или константой, и определяет длину фрагмента строки, представляющего дробную часть выводимого вещественного значения.
Выше описанное трудно себе представить, не увидев это воочию.
Тогда попробуем напечатать на экране несколько значений без форматирования, при этом в фигурных скобках укажем результат вывода в виде текстовой строки, где пробелы будем обозначать символом ‘X’:
begin
writeln( 'AAA' ); {AAA}
writeln( 'true' ); {true}
writeln( 63 ); {63}
writeln( 123 ); {123}
writeln( 1234.56789 ); {X1.2345678900E+03}
end.
Данный пример демонстрирует то, что можно получить при формировании таблицы значений на экране или в текстовом файле, и каким неровным будет образуемый столбик значений, где разные величины будут шарахаться из стороны в сторону в зависимости от длины фрагмента строки выводимого значения. Соответственно, вещественные значения будут напечатаны с указанием экспоненты и её степени, что любого пользователя, незнакомого с программированием, может ввести в заблуждение.
Для этого и существует возможность форматированного вывода текста. При этом, форматирование для разных значений немного отличается.
Так, для целых и совместимых с ними, а так же строчных и булевых типов формат оператора может состоять из указания переменной или константы, значение которой необходимо напечатать, двоеточия и переменной или константы (Width), указывающей минимальную длину, которую должна иметь строка. Если длина строки будет меньше указанной, то эта строка дополняется пробелами слева, а если больше указанной, то строка останется неизменной. Вообще, можно указать хоть целый список таких пар “Var:Width” через запятую. Пример, где символ ‘X’ означает символ пробела:
begin
writeln( 'AAA':5 ); {XXAAA}
write( 'true':5 ); {Xtrue}
write( F, 63:5 ); {XXX63}
writeln( 123:5 ); {XX123}
writeln( F, 123:2 ); {123}
end.
Такое форматирование может существенно помочь в формировании таблицы. Хочу заметить, что при выводе не вещественных значений, параметр Decimals просто игнорируется, поэтому не имеет смысла его указывать.
Что касается форматированного вывода вещественных значений, то он может состоять из печатаемой переменной или константы, двоеточия, параметра Width, ещё одного двоеточия, и параметра форматирования дробной части (Decimals). Аналогично, можно указать целый список таких триад “Var:Width:Decimals” через запятую. Параметр Width указывает общую длину строки с учётом целой и дробной частей и точки, их разделяющей. Выравнивание дробной части будет выполнено так, что если длина фрагмента строки дробной части больше заявленной в Decimals, то фрагмент строки будет укорочен до заявленной. Если длина фрагмента строки дробной части меньше заявленной, то фрагмент строки будет дополнен справа нулями (учтите, что символ ‘X’ в фигурных скобках означает пробел):
begin
writeln( 1234.56789 ); {X1.2345678900E+03}
writeln( 1234.56789:7 ); {X1.2E+03}
writeln( 1234.56789:7:2 ); {1234.57}
write( F, 1234.56789:7:6 ); {1234.567890}
writeln( 1234.56789:7:8 ); {1234.56789000}
writeln( 1234.56789:10:2 ); {XXX1234.57}
writeln( 1234.56789:16:8 ); {XXX1234.56789000}
writeln( F, 1.56789:13:8 ); {XXX1.56789000}
writeln( 5 + 10.1:8:2 ); {XXX15.10}
end.
Как показано в последней строке примера, форматирование допустимо и для выражений.
Вот собственно и весь фокус. В книгах разных авторов могут быть разные теоретические трактовки выше описанного форматированного вывода. Я постарался изложить наиболее близкое соответствие, так как оно основано на практике. Аналогично действует оператор Str для преобразования значений переменных в строку, с тем лишь отличием, что указать для преобразования можно только одну переменную, а не целый список:
Str( V [: width [: decimals >; var S : string )
где V – переменная, значение которой должно быть преобразовано в строку S. При этом, тип переменной V может быть только целым или вещественным.
Как я уже говорил, в операторе Write, в качестве параметров форматирования Width и Decimals могут быть указаны не только константы, но и переменные, что позволяет осуществлять настраиваемое форматирование за счёт изменения значений оных в ходе выполнения программы.
Нетипизированные файлыИзучив типизированные и текстовые файлы, мы наконец подкатились к рассмотрению нетипизированных файлов, то есть файлов, в которых элемент может иметь произвольный тип, но строго определённой длины. При этом допускается произвольная интерпретация каждого элемента. Что это всё значит? А это значит, что работа с такими файлами позволяет вводить и выводить различное количество элементов любого файла независимо от их структуры.
Для работы с нетипизированными файлами необходимо объявить файловую переменную с использованием единственного служебного слова file:
var FileData : file;
и открывать файл следует известными процедурами Reset или Rewrite, где вторым параметром должен быть указан размер элемента файла (записи) в байтах:
Assign( FileData, ’pic.bmp’ );
Rewrite( FileData, 512 );
Если второй параметр не указан, то по умолчанию размер записи считается равным 128 байтам. При этом следует учесть, что размер сектора диска равен 512 байтам, и для ускорения обмена данными следует размер записи делать кратным размеру сектора. Так же может возникнуть ситуация, когда размер файла не кратен 512-ти и тогда очередная запись будет заполнена не полностью. Лично я всегда использую размер записи, равный одному байту – это позволяет читать весь файл без проблем.
Для ввода-вывода информации предусмотрены две стандартные процедуры:
BlockRead(var F:file; var Buf; Count:word [; var Result:word]) читает из открытого файла, представленного файловой переменной F данные Count записей в переменную Buf, и если указан параметр Result, то в него возвращает количество реально прочитанных полных записей. Чтение производится с текущей позиции указателя файла. Таким образом, проверяя значение параметра Result, можно отследить возникновение ошибки, произошедшей в следствие не кратности размера файла размеру записи или исчерпание файла и, тем самым, отключить системную обработку ошибок, связанных с этой операцией. Если параметр Result опустить, то при возникновении выше описанной аварийной ситуации произойдёт ошибка выполнения программы “Error 100: Disk read error.” (ошибка чтения диска). Пример:
var Arr : array [0..511] of byte;
d : word;
begin
Assign( FileData, 'pic.bmp' );
Reset( FileData, 512 );
Blockread( FileData, Arr, 1, d );
Close( FileData );
end.
BlockWrite(var F:file; var Buf; Count:word [; var Result:word]) выполняет вывод Count записей из переменной Buf в открытый файл, представленный файловой переменной F. Назначение параметра Result аналогично, и ошибка может возникать при нехватке места на диске. Запись производится с текущей позиции указателя файла. Пример:
begin
Assign( FileData, 'pic.bmp' );
Rewrite( FileData, 1 );
Blockwrite( FileData, Arr, SizeOf(Arr) );
Close( FileData );
end.
Следует помнить, что размер переменной Buf должен быть не меньше, чем Count*Размер_Записи. Ввод-вывод осуществляется с первого байта области памяти, которую занимает переменная Buf.
Если переменная Buf объявлена как массив, то может быть указан индекс массива:
Blockread( FileData, Arr[10], 15, d );
и тогда данные будут прочитаны в массив Arr начиная с первого байта 10-го элемента массива.
При работе с нетипизированными файлами можно применять следующие подпрограммы:
Seek – позиционирует указатель файла на указанную запись, а если размер записи равен 1 байту, то на указанный байт файла.
FileSize – возвращает размер файла в полных записях, то есть значение будет ровняться Размер_файла_в_байтах Div Размер_записи. Если размер записи 1 байт, то возвращает размер файла в байтах.
FilePos – возвращает номер записи, на которую установлен текущий указатель файла. Соответственно, если размер записи 1 байт, то возвращает номер байта, на который установлен указатель файла.
Продолжение следует…
© Владислав Демьянишин
Вы находитесь на официальном сайте Владислава Демьянишина - разработчика игры Dune IV (Dune 4). На нашем сайте Вы можете бесплатно скачать игры Dune IV (Dune 4), Battle City (Танчики с Dendy/Nintendo), читы к играм и многое другое. Также Вы можете скачать бесплатно программы и полезные утилиты. Все программы чистые, т.е. не содержат вирусов и иного вредоносного ПО.
Среди доступных программ есть мобильная читалка книг, менеджер переноса файлов с фото- и видеокамер на компьютер, текстовый редактор, WYSIWYG редактор, 3D аниматор, GIF аниматор, AVI аниматор, пакетный конвертор изображений, редактор электрических схем, программа для скриншотов, диспетчер тем рабочего стола и другие.
На нашем сайте можно не только бесплатно скачать игры, но и документацию и книги по программированию на MIDLetPascal, Turbo Pascal 6, Turbo Pascal 7, Borland Pascal, по программированию устройств Sound Blaster, Adlib, VESA BIOS, справочник Norton Guide и много другой полезной информации для программистов, включая примеры решения реальных задач по созданию резидентных программ. Предлагаю также посетить Марья искусница - сайт о рукоделии (http://mariya-iskusnica.ru).
Журнал > Программирование > Паскаль для новичков (Turbo Pascal, Assembler) > Паскаль для новичков (часть 29): Текстовые файлы
![]()
| ||||||||||||||||||||||||
|
||||||||||||||||||||||||
|