Здравствуйте. Установлена RAD Studio 11.3, у которой отсутствует вкладка BDE и, соответственно, компонент Table, который обеспечивает доступ к таблице средствами механизма BDE.
|
Работа с текстовыми файлами
Общие принципы работы с файлами
В предыдущих примерах мы сохраняли текст в файл и считывали текст из файла при помощи свойств:
Memo1.Lines.SaveToFile() Memo1.Lines.LoadFromFile()
Этот метод удобен и хорош, однако он не позволяет нам контролировать весь процесс записи в файл и чтения из файла. То есть, эти функции весь процесс чтения и записи выполняют скрыто от нас.
Однако бывает, когда программист испытывает необходимость контроля этих процессов, кроме того, не для всех типов эти функции доступны. Например, у нас есть текст в строковой переменной. Мы уже говорили, что строковая переменная может хранить почти неограниченное количество символов, то есть в переменную мы можем записать весь текстовый файл, включая и символы перехода на другую строку и возврата каретки (#13 #10). С функциями SaveToFile() и LoadFromFile() могут работать данные, которые имеют тип TStrings, а простые строки не могут их вызывать. Поэтому приходится делать записи в файл напрямую, и также напрямую их считывать.
Для работы с файлами многие программисты предпочитают использовать функции WinAPI. Несмотря на грозное звучание, ничего особо сложного в этих функциях нет, тем не менее, такие функции имеют один крупный недостаток. Корпорация MicroSoft постоянно вносит какие-то изменения в свои операционные системы. Так, в первых версиях Windows, для чтения файлов использовалась функция WinAPI _lread. Потом появилась функция ReadFile и Microsoft стала рекомендовать использовать в программировании именно ее. А затем появилась функция ReadFileEx, которая позволяет работать с файлами больших размеров. После каждого изменения этих функций очень часто приходится переделывать всю программу, чтобы она могла работать с новой операционной системой. А это отнимает много времени и создает дополнительные неудобства и для программистов, и для пользователей.
Поэтому в Delphi рекомендуется использовать встроенный специализированный объект TFileStream. Если Microsoft введет какие-то новшества, Borland учтет их в объекте, и нам останется лишь перекомпилировать нашу программу, не меняя ее кода. Кроме того, использование TFileStream намного проще, чем функции WinAPI. TFileStream - это объект, и как каждый объект, его нужно вначале объявить, а затем проинициализировать.
Первым делом необходимо создать переменную типа TFileStream:
var f : TFileStream;
Таким образом, мы объявили переменную типа объект TFileStream, и в дальнейшем можем работать с этой переменной, как с объектом. То есть, указывать имя этой переменной, а после точки выбирать свойства, методы и события этого объекта. Однако объявить переменную мало, требуется еще проинициализировать ее.
f := TFileStream.Create(параметры);
У метода Create объекта TFileStream может быть три параметра, причем третий параметр необязателен, его можно не указывать. Разберемся с этими параметрами.
Имя файла – этот параметр – простая строка, которая может содержать только имя файла, или полное имя файла, включая и адрес.
Режим открытия. Здесь можно указать один из следующих параметров:
- fmCreate – Создать файл с указанным в первом параметре именем. Если файл уже существует, он откроется в режиме для записи.
- fmOpenRead – Открыть файл только для чтения. Если файл не существует, произойдет ошибка, поэтому прежде требуется выполнить проверку на существование файла. Запись в файл в этом режиме невозможна.
- fmOpenWrite – Открыть файл для записи. При этом текущее содержимое файла уничтожается, и файл перезаписывается.
- fmOpenReadWrite – Открыть файл для редактирования, то есть, и чтения, и записи.
Права, с которыми будет открыт файл. Этот параметр необязателен, его можно не указывать. Он имеет следующие возможные значения:
- fmShareCompat – Другие приложения тоже имеют право работать с открытым файлом.
- fmShareExclusive – Другие приложения не смогут открыть файл.
- fmShareDenyWrite – Другие приложения смогут открыть файл только для чтения, записать в него данные они не смогут.
- fmShareDenyRead – Другие приложения смогут открыть файл только для записи, для чтения они не смогут его открыть.
- fmShareDenyNone – не мешать другим приложениям работать с файлом.
Пример:
f := TFileStream.Create('C:\MyFile.txt', fmOpenReadWrite, fmShareExclusive);
Для чего нужны права доступа к файлу? Например, текстовый файл может быть открыт стандартной программой "Блокнот", этот же файл мы можем открыть из нашего собственного текстового редактора. Редактор менеджера файлов FAR также может открыть этот текстовый файл. И программа MS Word тоже может его открыть! Теперь предположим, что наша программа делает запись в файл. В это же самое время какая-то другая программа также сохраняет изменения в этом файле. Наша программа сделала изменения и закрыла файл, а другая программа даже не подозревает об этих изменениях, и просто перезаписывает файл со своими изменениями. Таким образом, наши изменения просто теряются!
То же самое может произойти, если ваша программа выполнена в сетевом варианте. Например, есть какой-то специальный файл, в который сотрудники отдела записывают свои изменения. Этот файл может находиться на каком-то сетевом диске, и доступ к этому файлу имеет каждый сотрудник. И у каждого сотрудника установлена ваша программа. Таким образом, если одновременно двое сотрудников будут производить изменения в файле, то данные одного из них потеряются, так как программа другого перезапишет файл без учета этих изменений. Если вы пишете однопользовательскую программу, и доступ к файлу будет иметь только она, то про третий параметр можете вовсе забыть.
После того, как Вы создали объект, проинициализировали его и поработали с ним, файл нужно закрыть и освободить память, занимаемую этим объектом. Для этого достаточно вызвать метод:
f.Free;
Теперь осталось разобраться со структурой файла, и методами чтения из него, и записи в него. Начнем со структуры.
Когда вы только открыли файл, позиция курсора устанавливается на начало, и любая попытка чтения или записи будет применена к этой позиции курсора. Чтобы прочитать (записать) в другую позицию, требуется передвинуть курсор. Для этого используют метод Seek, который имеет два параметра:
- Число, указывающее количество байт (символов), на которые требуется передвинуть курсор.
- Откуда нужно двигаться. Тут может быть три варианта:
- SoFromBeginning – двигаться на указанное количество байт от начала файла.
- SoFromCurrent – двигаться от текущей позиции курсора.
- SoFromEnd – двигаться на указанное количество байт от конца файла к его началу.
Итак, чтобы передвинуть курсор от начала файла на 10 байт, нужно выполнить команду:
f.Seek(10, soFromBeginning);
Метод Seek – это функция, она всегда возвращает количество байт смещения от начала файла. Этим свойством можно воспользоваться, чтобы узнать общее количество байт в файле:
Размер_Файла := f.Seek(0, soFromEnd);
Правда, если нам требуется просто посмотреть размер файла, то этот трюк не совсем подходящий: нам придется открыть файл, переместиться в его конец, и затем закрыть его. Как узнать размер файла более подходящим способом, узнаем позже.
Для чтения из файла нужно использовать метод Read, у которого тоже есть два параметра:
- Переменная, в которую будет записан прочитанный текст.
- Количество байт, которые следует прочитать.
Разберем пример чтения из файла 10 символов, начиная с 15-й позиции:
var f : TFileStream; //объявляем переменную buf : array [0..10] of Char; //буфер для хранения прочитанных данных begin //открываем файл filename.txt для чтения и записи: f := TFileStream.Create('c:\filename.txt', fmOpenReadWrite); //перемещаемся на 15 символов вперед: f.Seek(15, soFromBeginning); //читаем в буфер 10 символов из установленной позиции: f.Read(buf, 10); Memo1.Lines.Add(buf); //скопировали эти 10 символов в Memo //уничтожаем объект и тем самым закрываем файл: f.Free; end;
Метод Read возвращает количество реально прочитанных байт. Оно должно быть равно тому количеству байт, которые мы указали при вызове этого метода. Есть две причины, по которым это количество может быть не равно указанному:
- При чтении был достигнут конец файла, и функция прочитала меньше байт, чем планировалось.
- Ошибка на диске или любая другая проблема.
Для записи в файл используется метод Write. Есть два параметра и у него:
- Переменная, содержимое которой нужно записать.
- Число байт для записи.
Пользоваться методом записи можно точно также, как и методом чтения.
В "следующей лекции" мы продолжим изучение работы с файлами.