Delphi прочитать бинарный файл

Обновлено: 07.07.2024

Сохранение данных в типизированный файл.

Предварительные замечания.

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

Они будут необходимы нам в дальнейшем при работе с нетипизированными файлами.

Позиционирование указателя типизированного файла.

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

Для обращения к записи по её номеру существует процедура позиционирования:

seek(файловая_переменная, номер_записи) //помним, что отсчет ведутся от 0)

Создадим файл для хранения целых чисел. Запишем в него 5 значений. Проконтролируем записанные значения чтением из файла и отображение их в memo.

Определим размер файла функцией FileSize(ф.п.).

Затем установим указатель файла в четвёртую позицию (то есть номер_записи=3).

Изменим значение записи в этой позиции и вновь проконтролируем результат.

Для решения задачи подготовим форму:

типизированный файл в delphi

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

Создадим обработчики событий для первой и второй кнопок:

var vFileInt:File Of Integer; // создаём переменную для ссылки на типизированный файл

procedure TForm1.Button1Click(Sender: TObject);

rewrite(vFileInt); //создаём файл

j:=filePos(vFileInt); //контролируем положение указателя файла

write(vFileInt,j); //формируем значения и записываем их в файл.

j:=filePos(vFileInt); //опять контролируем положение указателя в файле

j:=fileSize(vFileInt); //проверяем размер файла (количество записей)

reset(vFileInt); //переоткрываем файл. При этом указатель файла устанавливается на 0.

while not EOF(vFileInt) do

read(vFileInt,j); //читаем файл и прочитанные значения отображаем в memo.

closeFile(vFileInt);

Форма после нажатия на первую кнопку:

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

procedure TForm1.Button2Click(Sender: TObject);

var j:integer; s:string;

reset(vFileInt);

seek(vFileInt,3); //устанавливаем указатель файла в четвёртую позицию (0,1,2,3)

write(vFileInt,j); //перезаписываем четвёртое значение

j:=filePos(vFileInt); //отображаем положение указателя файла после перезаписи.

reset(vFileInt);

while not EOF(vFileInt) do

read(vFileInt,j); //читаем и отображаем файл

closeFile(vFileInt);

Форма после нажатия на вторую кнопку:

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

Компонент TBitBtn

Продолжим знакомиться с компонентами. На вкладке Additional находится компонент TbitBtn.

Это кнопка с расширенным набором свойств.

Познакомимся с некоторыми из них, которые будут важны в данном занятии.

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

Для записи в поток подготовим кнопу типа TbitBtn и настроим её так, чтобы она имела в конечном итоге вид:

типизированный файл в delphi

Как видно из рисунка, на кнопке появилась пиктограмма (красный кружок), Название кнопки выведено в трёх строках. Изменён цвет шрифта.

Для отображения названия кнопки в нескольких строках посмотрим, как хранятся строки в компоненте memo.

В окне текст отображается в виде отдельных строк. А в свойстве Memo1.Text он хранится в виде:

типизированный файл в delphi

В Object Inspector нельзя добиться вставки этих служебных символов в строку. Они будут воспроизведены как простой текст.

Чтобы служебные символы сыграли свою роль, надо отдельно сформировать строку с их присутствием и записать в свойство Caption.

Удобнее всего это сделать в обработчике создания формы:

procedure TForm1.FormCreate(Sender: TObject);

begin

end;

Цвет символов можно изменить, раскрыв свойство Font, нажав на «+». В выпадающем списке Color можно выбрать нужный цвет символов.

Как видно на рисунке, для кнопки можно организовать подсказку. Для этого надо заполнить свойство Hint (в нашем случае там написано «подсказка») и разрешить её отображать (выставить свойство ShowHint в true).

И наконец, на кнопке отображена небольшая пиктограмма. Она подготавливается заранее в текстовом редакторе и загружается через свойcтво Glyph).

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

Простые и структурированные типы данных.

Под переменные стандартных типов отводится оговоренное количество байт памяти. Под Integer 4 байта, под Double 8 байт, под Char 1 байт и так далее.

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

Совокупность длины переменной и способа интерпретации последовательности байт можно назвать типом данных.

Указанные типы называются простыми типами данных.

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

Чтобы работать с типом данных «массив» надо хранить информацию о том, что мы имеем дело с последовательностью байт, где начинается эта

последовательность, указать общее количество байт и на какие «порции» надо делить эту последовательность (указать тип данных).

Обычный массив характерен тем, что длина всех элементов массива одинакова.

В отличие от него, динамический массив может иметь разную мощность по разным измерениям. Например, двумерный динамический массив может содержать по первому измерению 5 элементов, а по второму — 10.

Но тип всех элементов всё равно остаётся одинаковым. Например, Integer.

Тип данных «запись».

Объявляется запись следующим образом:

type tRec=record J:integer, sh:string[20]; ss:string; d:double; ar:array[1..3] of char; ex1,ex2:extended; end;

Нотация обращения к полям записи следующая:

vRec.d:=10.255; vRec.ex1:=456.89; vRec.ex2:=789.023;

Заметим, что полем может служить другая запись!

type tRec1=record JJ:integer, end;

type tRec=record J:integer, sh:string[20]; ss:string; d:double; ar:array[1..3] of char; ex1,ex2:extended; r1:tRec1 end;

Тогда для формирования значения JJ надо записать:

vRec.r1.JJ:=20;

Не прадо ли, очень похоже:

Form1.Memo1.Text ?

Теперь сделаем «петлю» и ещё раз вернёмся к типу «string».

Ещё раз о типе «string».

В типе «string» первые 12 байт служебные. В них указывается длина строки.

Номер кодовой таблицы символов (в какой язык интерпретировать числа, записанные в байтах, составляющих строку). Счётчик ссылок (он увеличивается на 1, когда выполняется s2:=s1, где s1 и s2 — строковые переменные).

Символы пронумерованы по порядку, начиная с 1. К символу номер N можно обратиться, записав s1[5]. Если, например, в s1 хранится слово «строка», то s1[4] вернёт символ «к».

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

Само обращение к данным происходит по ссылке (по адресу, который записан в переменной, объявленной как тип String).

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

Записи являются как бы предшественниками такого типа данных, как объект.

Понятие «объект» как особый тип данных.

К полям записи обращаются по нотации «переменная_запись»«.»«имя_поля».

Такая же нотация характерна и для объекта. Вспомним, что компоненты Delphi — это объекты, встроенные в IDE (в среду разработки).

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

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

К этим процедурам можно обращаться с помощью всё той же нотации с «точкой», как и к полям с данными.

Например, вспомним, как мы очищали содержимое компонента Memo (удаляли из него весь текст).

Для этого мы использовали процедуру (в объектах встроенные процедуры называются методами!) Clear. Так как ей не нужны параметры, её можно писать без скобок, то есть вместо Clear() записать просто Clear.

Поэтому мы использовали следующее предложение:

Form1.Memo1.Clear;

Сам объект Memo1 создаётся по шаблону (типу) Tmemo.

Более того. Сами типы являются объектами, поставляемыми со средой IDE. В них содержится метод (процедура) Create, называемый конструктором.

Собственно, он и создаёт экземпляр объекта в программе по собственному образу и подобию. Объект — тип может быть только один в пределах видимости IDE. Но своих копий (экземпляров) он может создать сколько угодно (конечно, каждому экземпляру должно быть дано уникальное имя).

В программе экземпляр объекта оформляется как переменная объектного типа.

Здесь объявлены переменная Form1 три переменных типа Tmemo.

var Form1: Tform1; Memo1:TMemo; Memo2:TMemo; Memo3:TMemo; и так далее.

Tform1, Tmemo и другие встроенные в IDE объекты-типы называются Delphi компонентами. При размещении компонента на форму IDE вызывает конструктор объекта-типа автоматически при размещении компонента на форму.

Замечание. На будущее — типы, по которым создаются объекты, в объектном программировании называются «классами (Class)».

Чтение бинарного файла
Добрый вечер дорогие программисты! Хотел бы понять как прочитать бинарный файл по его структуре.

Чтение строки из бинарного файла
Доброго времени суток ув. форумчане. Помогите советом. Имеется бинарный файл из которого.

Запись/чтение из бинарного файла. BlockRead
Впервые использую BlockRead и BlockWrite, видимо что то не правильно понял. Запись: i : Word; .

Чтение бинарного файла.
Здраствуйте, форумчане. Сегодня столкнулся с такой проблемой: Есть бинарник и в нем есть текст.

насколько я знаю, чтобы к строке так обращаться, ей либо надо задать длину, либо инициализировать сперва, так как это динамическая память тут вообще можно обойтись и типом Char, раз всего 1 символ читается, отпадает надобность использовать строку Arcor, подскажи пожалуйста как считать байты из бинарного файла и вывесте их в эдит? ну так чтобы читать, нужно знать, что читать, сколько читать, и как прочитанное трактовать! просто так файл прочитать на абум конечно же нельзя, структуру значть надо! Я только теперь увидел, что вы читаете эксешник, а что там лежит в самом "начале" - я понятия не имею, чтобы считывать так, как в примере выше Arcor, мне надо записать в конец файла и прочесть что написал. Я записать сумел. А как прочесть чтобы правильно символы выводились не знаю! У меня выводятся какие то иероглифы Arcor, еще 3 вопроса
1. Когда я записываю символы в exe то размер увеличивается на 2 байта. Я когда записывал размер изменялся на 1 байт(1 символ 1 байт), а тут почему то аж 2 байта. Может из за того что я использовал string?
2. Почему Вы использовали функцию WriteBuffer а не Write?(какая между ними разница?)
3. В процедуре считывания вы от F.Size отнемаете SizeOf(C). Я вот не пойму. Вы же не присвоили в процедуре считывания значения С. Откуда оно взялось? хотя смысл зачем Вы это делали я понял.
Я новичек в этом деле )) Хотелось бы разобраться хоть немного)) Гугл мне с этим редко помогает.

Решение

1. Юникод, анси, 2 и 1 байта
2. гугля в пользу
3. записываем в конец, далее прыгаем в конец, все мы в конце _____________________________A| <- вот тут мы после прыжка
чтобы прочитать, надо "отпрыгнуть" назад на нужное количество, в этом случае на размер чара юникодовского, т.е. на 2 байта назад
_____________________________|A <- стали тут, и теперь читаем "вперед"

в С я считываю результат чтения, через Read

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

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

Постановка задачи: Допустим, мне нужно в приложении Delphi сохранять некоторую информацию на диск. Мне не охото работать с текстовыми файлами, так как просмотр и обновление информации в них довольно муторное занятие. Преобладать будут операции записи и чтения, в то время как операции изменения и апдейта будут присутствовать в меньшей степени. Вся информация будет хранится в переопределённом типе данных Pascal Record. Итак, какой подход мне лучше всего использовать?

BDE плюс Paradox или Access, . спасибо, не надо. Не хотелось бы испытывать мороку с BDE. Использовать текстовые файлы ASCII ? Не пойдёт. Нужна хоть какая-то минимальная защита, а текстовые файлы "полностью видимы". Оказывается, ответ на данный вопрос кроется в Delphi, а именно в непечатных файлах (или файлы некоторых типов/бинарные файлы).

Файлы
В Delphi существует три класса файлов: typed, text, и untyped. Файлы typed - это файлы, которые содержат данные определённого типа, такие как Double, Integer или предварительно определённый тип Record. Текстовые файлы содержат читаемые символы ASCII. Файлы Untyped используются в том случае, если мы хотим работать с файлом через определённую структуру.

Файлы Typed
В отличие от тектовых файлов, которые содержат строки, завершающиеся комбинацией CR/LF, файлы typed содержат данные, взятые из определённой структуры данных.

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

Перед тем, как мы сможем записать информацию на диск, нам необходимо объявить переменную типа file. Следующая строка объявляет переменную файла F:

Обратите внимание: Чтобы создать файл typed в Delphi, мы используем следующий синтакс:
var SomeTypedFile : file of SomeType
Базовый тип (SomeType) для файла может быть скалярным (наподобие Double), массивом или записью. Он не может быть длинной строкой, динамическим массивом, классом, объектом или указателем.

Чтобы начать работать с файлом из Delphi нам надо связать файл на диске с переменной файла в нашей программе. Для этого используем процедуру AssignFile.

Как только связь с внешним файлом установлена, переменную F необходимо 'открыть' для подготовки её к чтению или записи. Для открытия существующего файла мы используем процедуру Reset либо Rewrite для создания нового файла. После того, как программа закончит обработку файла, его необходимо закрыть при помощи процедуры CloseFile. Сразу после закрытия файла, связанный с ним внешний файл будет обновлён. Затем переменную файла можно связать с другим внешним файлом. Вообще, мы должны всегда производить обработку исключительных ситуаций, так как при работе с файлами может происходить довольно много ошибок. Например, если мы вызовем CloseFile для файла, который уже закрыт, то Delphi выдаст ошибку I/O. С другой стороны, если мы попробуем закрыть файл, до вызова AssignFile, то результаты могут быть непредсказуемыми.

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

Чтение
Для получения всей информации из файла 'members.dat' используется следующий код:

Обратите внимание: Eof это функция проверки конца файла (EndOfFile). Мы используем эту функцию, чтобы не выйти за пределы файла (за пределы последней, сохранённой записи).

Поиск и позиционирование
Обычно, доступ к файлам осуществляется последовательно. При чтении из файла (используя стандартную процедуру Read) или при записи (используя стандартную процедуру Write), текущая позиция в файле перемещается на следующий по порядку компонент (следующая запись). К файлам typed так же можно обращаться через стандартную процедуру Seek, которая перемещает текущую позицию в файле на указанный компонент. Для определения текущей позиции в файле и размера файла можно использовать функции FilePos и FileSize.

Изменение и обновление
Мы разобрались как записывать и считывать из файла массив Members. А что, если нам нужно найти десятую запись и изменить в ней e-mail? Давайте посмотрим на процедуру, которая делает это:

Всё готово
Итак, теперь мы имеем всё, что нам нужно для реализации нашей задачи. Мы можем записать информацию на диск, считать её, и даже изменить некоторые данные (например, e-mail) в "середине" файла.
Самое главное, что этот файл не в ASCII формате, и вот как выглядит в Notepad (только одна запись):

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

обычно вы не должны читать файлы байт за байтом. Используйте BlockRead с большим значением (512 или 1024 часто лучше всего) и используйте его возвращаемое значение, чтобы узнать, сколько байтов было прочитано.

Если размер не слишком велик (и ваше использование SetLength, похоже, поддерживает это), вы также можете использовать один вызов BlockRead, читающий полный файл сразу. Итак, изменив свой подход, это будет:

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

Если вы действительно хотите быстро прочитать двоичный файл, пусть windows беспокоится о буферизации ; -) с помощью Сопоставленные С Памятью Файлы. Используя это, вы можете просто сопоставить файл с местоположением памяти и прочитать его как массив.

ваша функция станет:

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

В TMappedFile из моей статьи Быстрое чтение файлов с помощью карты памяти, эта статья также содержит пример того, как использовать его для более "продвинутых" двоичных файлов.

Это зависит от формата файла. Если он состоит из нескольких одинаковых записей, вы можете решить создать файл этого типа записи.

Если это достаточно длинный файл, чтение которого таким образом занимает заметное количество времени, я бы использовал поток. Чтение блока будет намного быстрее, и нет никаких петель, о которых нужно беспокоиться. Что-то вроде этого:--3-->

из вашего кода видно, что ваш размер записи составляет 1 байт. Если нет, то измените строку читать:

или что-то подобное.

Поиск буферизованного потомка TStream. Это сделает ваш код намного быстрее, так как чтение диска выполняется быстро, но вы можете легко выполнить цикл через буфер. Есть разные О, или вы можете написать свой собственный.

Если вы чувствуете себя очень растерянным, вы можете полностью обойти Win32 и вызвать функцию NT Native API ZwOpenFile (), которая в моем неофициальном тестировании немного сбривается. В противном случае, я бы использовал решение сопоставленного файла памяти Дэви выше.

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