А ты пиши мне письма мелким почерком, поскольку места мало в рюкзаке.
Фильменная песня
Романтическое создание писем при дрожащем пламени свечи, увы, безвозвратно ушло в прошлое. И хотя некоторые креативные приверженцы эпистолярного стиля упорствуют в невежестве и доверяют свои невнятные мысли бумаге, последняя сейчас в основном используется по своему прямому назначению, то есть для складывания фигурок оригами и издания плакатов, призывающих беречь зелёного друга (коим для нас является лес, а не крокодил Гена и не пьяный товарищ).
Все наши винчестеры, флешки, диски CD- и DVD-ROM доверху забиты файлами. Каждый из них имеет имя и - почти всегда - расширение, которое следует за последней точкой в имени файла и обычно указывает на назначение файла и формат данных, хранящихся в нём.
Систематика файлов насчитывает многие сотни типов файлов: исполняемых exe, видео avi, mpg, звуковых ogg, wav, музыкальных mp3, mid, но, с точки зрения Delphi, разновидностей файлов всего 3: текстовые (они имеют тип TextFile), типизированные и нетипизированные.
На этом занятии мы рассмотрим текстовые файлы, которые состоят из строк, подобных тем, что мы изучили на прошлом уроке. Как в текстовых, так и в любых других файлах размещаются данные, которые можно сколь угодно долго хранить на диске даже после окончания работы с приложением, в котором эти данные были созданы, а потом снова загрузить в него.
Наберите в самом простом текстовом редакторе любой сумбурный текст, который только придёт вам в голову, - его глубокий смысл только отвлечёт нас от формы
Очень хорош для разбора текстовых файлов стандартный Блокнот, который не добавляет в файл никакой «отсебятины», в отличие от «продвинутых» редакторов типа MS Word.
Не забудьте после набора текста нажать клавишу Return, чтобы завершить строку. Сохраните текст в файле под каким-нибудь именем - вот и готов настоящий текстовый файл! Обратите внимание, что к его названию автоматически добавлено расширение .txt. Теперь вы можете открыть файл в любом редакторе и увидеть вашу строку в первозданном виде (естественно, все ваши труды по форматированию текста пойдут прахом, потому что никакая информация о ваших шрифтовых предпочтениях не сохраняется!).
Когда мы изучали строки, то узнали, что разные типы строк по-разному хранятся в памяти компьютера. И вас, наверное, удивит тот факт, что на диске любые строки сохраняются одинаково, но не совсем так, как в ячейках памяти.
Если мы загрузим текст в редактирующую программу, то он будет разбит на строки так, как мы и его набирали. Но как редактор определяет конец строки? Может быть, вместе с каждой строкой записывается и её длина или после строки записывается нулевой символ? Второй вариант ближе к истине, но всё равно ошибочен.
В обычном текстовом редакторе мы никогда не увидим, что же там, в конце строки, поэтому воспользуемся таким текстовым редактором, который позволяет просматривать текст в 16-ричном виде, например, подойдёт WinHex
И вот мы видим: все символы строки записаны без всяких изменений, но в конце строки находятся сразу 2 символа - $0D и $0A (или то же самое в более привычном десятичном виде - #13 и #10). Они ещё в стародавние времена обозначали возврат каретки принтера и переход на новую строку. Этот анахронизм сохранился до сих пор в текстовых файлах, которые ничего и не знают о принтерах.
Нам осталось узнать, как же записываются строки таким причудливым образом, поэтому рассмотрим основные операции с текстовыми файлами - сохранение их на диске и загрузку в приложение. Они не доставят вам хлопот, если вы будете точно следовать «рецепту».
Независимо от того, сохраняем мы файл или загружаем его, первым делом нужно объявить файловую переменную типа TextFile:
var F: TextFile;
Её принято обозначать буквой F (от слова File, файл), но это необязательно. Именно эта переменная и будет псевдонимом реального файла.
Затем нужно связать файловую переменную с именем файла, воспользовавшись процедурой
procedure AssignFile(var F: file; FileName: string);
Её легче понять на конкретном примере.
Вот так можно связать нашу файловую переменную с файлом «osh_frc_v.txt» (так как путь к файлу не указан, то файл должен находиться в той же папке, что и само приложение!).
AssignFile(F, 'osh_frc_v.txt');
или
var s: string;
s:= 'osh_frc_v.txt'; // строка s содержит имя файла AssignFile(F, s);
Теперь можно открыть файл для чтения или записи.
Для считывания данных указанный файл должен существовать на диске. Чтобы открыть его, пользуемся процедурой
procedure Reset(var F: file); (в нашем примере - Reset(F); ) ,и можно загружать данные. Они будут считываться, начиная с первой строки.
Если файл уже был ранее открыт, то он сначала автоматически закрывается, чтобы не потерять данные, а потом вновь открывается.
Чтобы сохранить данные в файле, воспользуемся процедурой
procedure Rewrite(var F: file); (в нашем примере - Rewrite(F); )
Она создаст новый файл с заданным именем и откроет его для записи. Будьте осторожны: если файл с таким именем уже имеется на диске, он будет уничтожен! Поэтому безопаснее записывать данные в существующий файл функцией
function Append(var F: Text): Integer; ( в нашем примере - Append(F); )
В этом случае новые строки будут добавлены в файл за последней строкой, так что все прежние данные не пострадают.
4. Для записи данных в файл служат процедуры
procedure Write(var F: file [; P1; ...; Pn]);
procedure Writeln(var F: file [; P1; ...; Pn]);
В квадратных скобках записаны необязательные параметры, которые являются выражениями следующих типов: char, string, PChar, integer, real, boolean. Таким образом, в текстовый файл можно записывать не только символы, слова, строки, но и числа (при записи выражений логического типа в файл выводятся слова TRUE и FALSE). Количество выражений в списке вывода может быть любым.
Если в одной строке файла процедурой Write сохраняются данные разных типов, то они будут записаны друг за другом без пробелов и других разделителей. Процедура Writeln делает то же самое, но затем закрывает строку в файле (добавляет в конец строки символы $0D$0A).
Например, процедура
Writeln(F, ’А ты пиши мне письма мелким почерком!’);
Запишет строку в кавычках (но без кавычек!). Или то же самое:
var s: string;
s:= ’А ты пиши мне письма мелким почерком!’;
Writeln(F, s);
Или
var s1,s2,s3,s4,s5,s6,s7: string; s1:= ’А ’;
s2:= ’ты ’; s 3:= ’пиши ’;
s4:= ’мне ’; s5:= ’письма ’; s 6:= ’мелким ’; s7:= ’почерком!’;
Writeln(F, s1,s2,s3,s4,s5,s6,s7);
Или
Writeln(F, ’А ’, ’ты ’, ’пиши ’, ’мне ’, ’письма ’, ’мелким ’, ’почерком!’);
Или
Writeln(F, ’А ’ + ’ты ’ + ’пиши ’ + ’мне ’ + ’письма ’ + ’мелким ’+ ’почерком!’);
Вы также можете смешивать константы и переменные:
Writeln(F, si + ’ты ’ + s3 + ’мне ’ + s5 + ’мелким ’ + s7);
Если у вас есть к тому большая нужда, вы можете записать в строку числа и логические константы:
Writeln (F, si + ’ты ’ + s3 + ’мне ’ + s5 + ’мелким ’ + s7, ’ ’,123, ’ ’, 321, ’ ’, 123 < 321);
Тогда на диске появится строка:
А ты пиши мне письма мелким почерком!
123 321 TRUE
Все числа при записи в файл должны отделяться друг от друга, по крайней мере, одним пробелом, знаком табуляции или кодами конца строки.
Процедура только с одним параметром - Writeln(F) - просто завершает строку, ничего в неё не записывая.
Процедуры Writeln и Write начинают записывать данные с первой строки файла, затем Writeln (!) последовательно переходит ко второй строке, третьей - и так далее до конца файла. С их помощью нельзя сохранить данные в произвольной строке файла, но можно записать нужное число пустых строк процедурой Writeln(F), а уже затем записать нужную строку.
Для чтения данных из текстового файла имеются процедуры:
procedure Read(var F: file [; V1; ...; Vn]);
В квадратных скобках записаны необязательные параметры, которые являются переменными следующих типов: char, string, integer, real, PChar. Количество переменных в списке ввода может быть любым.
Мы чаще будем использовать вторую процедуру (Readln) - чтобы считать целиком всю строку в указанную строковую переменную:
var
s: String;
Readln(F, S);
Если в одной строке записаны данные других типов через пробел, например, «123 321 TRUE», то их можно считать так:
var
s : String; n,m:integer;
Readln(F, n, m, s);
В результате выполнения этой операции значением целой переменной n будет число 123, целой переменной m - число 321, строковой переменной s - строка 'TRUE' (нельзя считать значение в логическую переменную!).
Не забывайте следить за соответствием типов переменных и считываемых данных, иначе возникнет ошибка!
Если процедура Readln считывает только часть данных из строки (в списке ввода меньше переменных, чем в строке), то оставшаяся часть строки будет пропущена.
Если переменные при вызове процедуры отсутствуют - Readln(F);, - то текущая строка в файле пропускается и далее считываются данные из следующей строки.
Если строка считывается в переменную типа короткой строки или PChar и имеет больше символов, чем указанная максимальная длина строки, то вводимая строка усекается.
При вводе символа из файла в переменную типа char читается только 1 символ, в том числе и коды конца строки.
Процедуры Read и Readln начинают считывать данные с первой строки файла, затем Readln (!) последовательно переходит ко вто-рой строке, третьей - и так далее до конца файла. С их помощью нельзя считать данные из произвольной строки файла, но можно пропустить нужное число строк процедурой Readln(F), а уже затем считать нужную строку.
5. После завершения операций с файлом он должен быть закрыт процедурой:
procedure CloseFile(var F: file);(в нашем примере - CloseFile(F); )
Никогда не забывайте одну из заповедей программирования: Уходя, гасите свет!