![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | 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)
| ||