![]() |
|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
![]() Подскажите, уважаемые, никак не получается, в делфи новичек...
В общем переделываю чужую программу.. там идет сохранение буфера в файл, вот такой кусок Код:
var bufferTemplate1 : PChar; template1Length, pTransfered : integer; FS: TFileStream; pTemplate : pointer; begin //Сохраняю шаблон в bufferTemplate1 template1Length := Bsdk_Template_GetSize(pTemplate); GetMem(bufferTemplate1, template1Length); result := Bsdk_Template_Save(pTemplate, bufferTemplate1, template1Length, pTransfered); // после этой функции, в bufferTemplate1 содержаться данные //Сохраняю буфер bufferTemplate1 в файл Param1 + '.dat' FS := TFileStream.Create(Param1 + '.dat', fmCreate); FS.WriteBuffer(bufferTemplate1^, template1Length); FS.Free; FreeMem(bufferTemplate1); данные из bufferTemplate1 записываются в файл. Мне надо чтобы к этим данным еще записывалась кое-какая информация, ну например имя "Вася", "Петя", и соответственно потом это дело загрузить в память обратно. Делал через record, не получается: Код:
TTemplate = record Name: string[5]; Template: PChar; // тут пробовал разные варианты, не помогает end; var tTempl : TTemplate; FS: TFileStream; pTemplate : pointer; begin //Сохраняю шаблон в bufferTemplate1 template1Length := Bsdk_Template_GetSize(pTemplate); // SetLength(tTempl.Template, '2696'); GetMem(tTempl.Template, template1Length); result := Bsdk_Template_Save(pTemplate, tTempl.Template, template1Length, pTransfered); tTempl.name:= 'Вася'; FS := TFileStream.Create('c:\temp\test.dat', fmCreate); FS.WriteBuffer(tTempl, SizeOf(TTemplate)); FS.Free; FreeMem(tTempl.Template); // записывается только 8-10 байт, хотя должно быть не менее 2696 байт |
#2
|
||||
|
||||
![]() Примерно так:
Код:
var ..... len: Integer; s: AnsiString; begin ..... // Сохраняем FS := TFileStream.Create(Param1 + '.dat', fmCreate); FS.WriteBuffer(template1Length, SizeOf(template1Length)); // Сначала записываем размер даных FS.WriteBuffer(bufferTemplate1^, template1Length); // А потом сами данные s := 'Вася'; len := Length(s); FS.WriteBuffer(len, SizeOf(len)); // Сначала записываем длину строки FS.WriteBuffer(Pointer(s)^, len); // А потом саму строку FS.Free; ..... // Считываем FS := TFileStream.Create(Param1 + '.dat', fmOpenRead); FS.ReadBuffer(template1Length, SizeOf(template1Length)); // Сначала считываем размер даных GetMem(bufferTemplate1, template1Length); // Резервируем память под буфер требуемого размера FS.ReadBuffer(bufferTemplate1^, template1Length); // А потом считываем сами данные FS.ReadBuffer(len, SizeOf(len)); // Сначала считываем длину строки SetLength(s, len); // Резервируем память под строку требуемого размера FS.ReadBuffer(Pointer(s)^, len); // А потом считываем саму строку FS.Free; |
Этот пользователь сказал Спасибо poli-smen за это полезное сообщение: | ||
kti (21.11.2013)
|
#3
|
|||
|
|||
![]() Заработало! Спасибо огромное! т.е. по такому-же принципу я могу любые данные сохранить.. ясно
У меня еще пару вопросов ![]() 1) Для загрузки данных в программе используется конструкция через TMemoryStream: Код:
TS:= TMemoryStream.Create; TS.LoadFromFile(Param1); templateLength:=TS.Size; GetMem(BufferTemplate, templateLength); TS.Position:=0; TS.ReadBuffer(BufferTemplate^, templateLength); Чем этот подход принципиально может отличаться от Вашего (от TFileStream), почему был выбран именно TMemoryStream? 2) Мне нужно в этот-же файл дописывать данные. т.е например уже есть "Иванов", "Петров", мне нужно дописать в этот-же файл данные "Сидоров". Будет-ли работать такой вариант: Код:
// файл уже существует, с 2 записями, мне надо добавить 3 запись FS := TFileStream.Create('c:\temp\test.dat', fmOpenRead); // как-то надо спозиционировать FS на конец файла ?? FS.WriteBuffer(template1Length, SizeOf(template1Length)); // Сначала записываем размер данных FS.WriteBuffer(bufferTemplate1^, template1Length); // А потом сами данные |
#4
|
||||
|
||||
![]() Цитата:
Почему в той программе сделано через TMemoryStream я не знаю. Цитата:
Код:
FS.ReadBuffer(len, SizeOf(len)); // Считываем длину блока FS.Position := FS.Position + len; // Пропускаем ненужный блок (вместо его чтения) |
#5
|
|||
|
|||
![]() Цитата:
И как встать на конец файла перед записью нового потока? FS.Position = EOF ? так? чтобы данные дописались к файлу Код:
FS := TFileStream.Create('c:\temp\test.dat', fmOpenRead); // ?? FS.Position = EOF; // ??? // или нужно через FS.Position := FS.Position + len добираться до конца файла? FS.WriteBuffer(template1Length, SizeOf(template1Length)); // Сначала записываем размер данных FS.WriteBuffer(bufferTemplate1^, template1Length); // А потом сами данные |
#6
|
|||
|
|||
![]() Все! разобрался сам. Достаточно было почитать про файловые потоки..
Код:
FS := TFileStream.Create('c:\temp\test.dat', fmOpenReadWrite); FS.Seek(0, soFromEnd); // FS.WriteBuffer(template1Length, SizeOf(template1Length)); // Сначала записываем размер данных FS.WriteBuffer(bufferTemplate1^, template1Length); // А потом сами данные Остался один вопросик, что делает конструкция: Код:
FS.create(FileName, fmCreate or fmOpenWrite) т.е. если файл существует, то открывает для чтения/записи, а если нет то создает? Если это так, то это то, что мне нужно |
#7
|
|||
|
|||
![]() Еще вопросик
![]() Как мне узнать (при чтении потока) что файл кончился? И вообще как правильно обрабатывать ошибки чтения из потока? Например, я читаю какой-то блок Код:
FS.ReadBuffer(template1Length, SizeOf(template1Length)); // узнаем размер GetMem(bufferTemplate1, template1Length); // выделяем память FS.ReadBuffer(bufferTemplate1^, template1Length); // считываем данные например размер блока 2000 байт, а реально в файле 1000 байт. ReadBuffer вызовет исключение? как его обрабатывать? |
#8
|
||||
|
||||
![]() Цитата:
![]() Хотя изучение исходников, наверное, ещё большая сила. Цитата:
Во-вторых в Delphi7 нельзя с флагом fmCreate использовать никакие другие флаги (в новых версиях Delphi вроде это поправили), но фактически эффект будет таким будто с флагом fmCreate был использован флаг fmOpenReadWrite. Цитата:
Во-вторых метод ReadBuffer используется как правило для гарантированного чтения указанного количества байт. Например мы читаем некоторый конкретный формат файла и судя по спецификации считаем что далее можем прочитать определённое количество байт, а оказывается что их прочиталось меньше, из-за чего ReadBuffer вызовет исключение, что для нас будет означать что либо неверный формат файла или файл повреждён (недокачан). Ну а исключения обрабатываются через конструкцию "try..except" Если же нужно читать не гарантированное количество байт, а "сколько получится" - нужно вместо ReadBuffer использовать просто Read. Разница в том, что Read не вызовет исключения если прочиталось меньше байт чем указано и кроме того Read вернёт в результате сколько реально прочиталось байт, т.е. если мы пытались прочитать больше нуля байт, а Read вернула ноль, то значит мы уже в конце файла и читать из него больше нечего. |
#9
|
||||
|
||||
![]() Цитата:
Да, это я неправильно написал. Решил проблему через следующую конструкцию: Код:
if FileExists(Param1 + Name_DB) then begin FS := TFileStream.Create(Param1 + Name_DB, fmOpenReadWrite); FS.Seek(0, soFromEnd); // можно было FS.Position := FS.Size end else begin FS := TFileStream.Create(Param1 + Name_DB, fmCreate); end; Цитата:
Так? Цитата:
вот я и хочу вставить проверку на битый файл, например кто-то взял и удалил последние пару байт Цитата:
Понял, вот так и сделаю.. Еще раз спасибо |
#10
|
||||
|
||||
![]() Цитата:
Цитата:
Код:
if FS.Position = FS.Size then ShowMessage('Достигнут конец файла'); // или для надёжности можно проверять на "больше или равно": if FS.Position >= FS.Size then ShowMessage('Достигнут конец файла'); |
#11
|
|||
|
|||
![]() Цитата:
Почему?! У меня данные считываются блоками в цикле: Код:
while 1=1 do begin // сам шаблон не считываем, а пропускаем if FS.Read(template1Length, SizeOf(template1Length)) <= 0 then break; // Сначала считываем размер данных FS.Position := FS.Position + template1Length; // Пропускаем ненужный блок (вместо его чтения) if FS.Position >= FS.Size-1 then break; // файл кончился end; Если я буду сравнивать FS.Position >= FS.Size, то у меня начнется новый виток цикла (из-за этого 1000 байта), который мне совершенно не нужен. Например, 1000 байт, 5 блоков по 200 байт. Сделав 5 витков - Position будет равен 999, и проверка FS.Position >= FS.Size не сработает, и начнется 6 виток. Или я что-то не понимаю.. |
#12
|
||||
|
||||
![]() Цитата:
|
Этот пользователь сказал Спасибо poli-smen за это полезное сообщение: | ||
kti (26.11.2013)
|