![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
не верное копирование файла через BlockWrite/BlockRead
brother © (2009-05-15 08:52:00)Доброго времени суток!
Суть вот в чем:
Есть файл, из него читаю нужный объем байт и записываю в другой файл, код (черновой):
assignfile(FromF, 'c:\1.txt');
reset(FromF, 1);
seek(FromF, header.obj[spinedit1.Value]._seek);
count:=0;
AssignFile(ToF, 'c:\'+header.obj[spinedit1.Value]._shortname);
Rewrite(ToF, 1);
repeat
BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
inc(count, NumRead);
if count>header.obj[spinedit1.Value]._size
then
BlockWrite(ToF, Buf, count-header.obj[spinedit1.Value]._size, NumWritten)
else
BlockWrite(ToF, Buf, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead);
CloseFile(ToF);
Проблемма такая: при окончании копирования, на тестовом файле не дописывается 48 байт.
Отладчиком проверил все переменные:
header.obj[spinedit1.Value]._size = 50200 - корректно
inc(count, NumRead); увеличивает коррекно по 2048
count-header.obj[spinedit1.Value]._size на последнем шаге дает 1000.
не понимаю где я ошибаюсь?
brother (2009-05-18 09:57:00) [1]> и кошернее обернуть все это в объектную оболочку
подумаю, о кошерности) спасибо!
Slym (2009-05-18 09:53:00) [2]Slym © (18.05.09 9:31) [32]
и кошернее обернуть все это в объектную оболочку
типа
TFileContainer.Create(FileName);
TFileContainer.Count
TFileContainer.AddStream(FileName)
TFileContainer.AddFile(FileName)
TFileContainer.GetFileInfo(index)
TFileContainer.SaveToStream(index,path)
TFileContainer.SaveToFile(index,path)
brother (2009-05-18 09:47:00) [3]> Зочем? принято нумеровать от нуля...
чтоб спинедит не корректировать
Slym (2009-05-18 09:31:00) [4]brother © (18.05.09 9:27) [31]
FileIndex-1
Зочем? принято нумеровать от нуля...
brother (2009-05-18 09:27:00) [5]да поправил уже спасибо!
зы Offset:=SizeOf(Header)+ (FileIndex-1)*SizeOf(TObj2); ;))))
Slym (2009-05-18 09:15:00) [6]
procedure GetFileExample(const SourceFileName,DestDir:string;const FileIndex:integer);
var
Source,Dest:TFileStream;
Header:THeader;
Obj:TObj;
Offset:integer;
begin
Source:=TFileStream.Create(SourceFileName,fmOpenRead);
try
Source.ReadBuffer(Header,SizeOf(Header));
Offset:=SizeOf(Header)+ FileIndex*SizeOf(TObj);
if Source.Seek(Offset,soBeginning)<> Offset then raise Exception.Create('bad file');
Source.ReadBuffer(Obj,SizeOf(Obj));
with Obj do
begin
if Source.Seek(_seek+_size,soBeginning)<>(_seek+_size) then raise Exception.Create('bad file');
if Source.Seek(_seek,soBeginning)<>_seek then raise Exception.Create('bad file');
Dest:=TFileStream.Create(IncludeTrailingPathDelimiter(DestDir)+_shortname,fmCreate);
try
Dest.CopyFrom(Source,_size);
finally
Dest.Free;
end;
end;
finally
Source.Free;
end;
end;
brother (2009-05-18 08:34:00) [7]> procedure GetFileExample(const SourceFileName,DestDir:string;
> const FileIndex:integer);
только ты его не используешь, и несмторя на:
> GetFileExample('c:\1.txt','c:\', 1);
грузишь последний добавленый файл)
brother (2009-05-18 08:26:00) [8]> файл записанный моим кодом прекрасно читается моим же способом
да все ок...
Slym (2009-05-18 08:17:00) [9]файл записанный моим кодом прекрасно читается моим же способом
Slym (2009-05-18 08:12:00) [10]packed record?
brother (2009-05-18 08:09:00) [11]> так убери... мой пример приведен для убранного...
я убрал конечно, ошибка: Cannot create file c:\абракадабра...
> Source.ReadBuffer(Obj,SizeOf(Obj));
прилетает мусор
Slym (2009-05-18 08:07:00) [12]brother © (18.05.09 7:58) [23]
так убери... мой пример приведен для убранного...
я тебе объясняю у тебя поле статичной длинны а это неправильно
я сделал динамической длинны
brother © (18.05.09 7:56) [22]
Offset:=SizeOf(Header)+(Header.maxobj-1)*SizeOf(TObj);
где тут получение: _seek+_size итд? ты же вроде как эти данные даж не записывал?
Offset:=SizeOf(Header)+(Header.maxobj-1)*SizeOf(TObj);
if Source.Seek(Offset,soBeginning)<> Offset then raise Exception.Create('bad file');
Source.ReadBuffer(Obj,SizeOf(Obj));
получение
brother (2009-05-18 07:58:00) [13]
THeader = record
caption:string[10];
version:string[3];
size : longword ; // размер Header
maxobj : integer; // всего добавлено файлов
obj : array [1..30] of TObj;
end;
я их специально в хедер поместил, чтобы прочитав хедер, знать и размер и смещения и шортимя...
brother (2009-05-18 07:56:00) [14]> GetFileExample('c:\1.txt','c:\',1);
ошибка: Cannot create file c:\абракадабра...
Source.ReadBuffer(Obj,SizeOf(Obj));
читает мусор, я так не понимаю причем тут:
Offset:=SizeOf(Header)+(Header.maxobj-1)*SizeOf(TObj);
где тут получение: _seek+_size итд? ты же вроде как эти данные даж не записывал?
Slym (2009-05-18 07:37:00) [15]brother © (18.05.09 7:10) [19]
как раз гарантированный размер! игнорируя алигны полей
Slym (2009-05-18 07:36:00) [16]код записи без дозаписи/перезаписи
type
TObj = packed record
_shortname : string[100]; // имя файла без путей
_size : longword ; // размер файла
_seek : longword ; // смещение относительно начала файла
end;
THeader = packed record
caption:string[10];
version:string[3];
size : longword ; // размер Header
maxobj : integer; // всего добавлено файлов
end;
procedure CreateFileExample(const DestFileName:string;const FileNames:array of string);
var
Dest,Source:TFileStream;
Header:THeader;
Objs:array of TObj;
i:integer;
begin
Header.caption:='Write test';
Header.version:='1.0';
Header.maxobj:=Length(FileNames);
Header.size:=SizeOf(THeader)+SizeOf(TObj)*Header.maxobj;
SetLength(Objs,Header.maxobj);
Dest:=TFileStream.Create(DestFileName,fmCreate);
try
Dest.Size:=Header.size;
Dest.Position:=Header.size;
for i:=0 to Header.maxobj-1 do
begin
Source:=TFileStream.Create(FileNames[i],fmOpenRead);
try
with Objs[i] do
begin
_shortname:=ExtractFileName(FileNames[i]);
_size:=Source.Size;
_seek:=Dest.Position;
end;
Dest.CopyFrom(Source,0);
finally
Source.Free;
end;
end;
Dest.Seek(0,soBeginning);
Dest.WriteBuffer(Header,SizeOf(Header));
for i:=0 to Header.maxobj-1 do
Dest.WriteBuffer(Objs[i],SizeOf(TObj));
finally
Dest.Free;
end;
end;
procedure GetFileExample(const SourceFileName,DestDir:string;const FileIndex:integer);
var
Source,Dest:TFileStream;
Header:THeader;
Obj:TObj;
Offset:integer;
begin
Source:=TFileStream.Create(SourceFileName,fmOpenRead);
try
Source.ReadBuffer(Header,SizeOf(Header));
Offset:=SizeOf(Header)+(Header.maxobj-1)*SizeOf(TObj);
if Source.Seek(Offset,soBeginning)<> Offset then raise Exception.Create('bad file');
Source.ReadBuffer(Obj,SizeOf(Obj));
with Obj do
begin
if Source.Seek(_seek+_size,soBeginning)<>(_seek+_size) then raise Exception.Create('bad file');
if Source.Seek(_seek,soBeginning)<>_seek then raise Exception.Create('bad file');
Dest:=TFileStream.Create(IncludeTrailingPathDelimiter(DestDir)+_shortname,fmCreate);
try
Dest.CopyFrom(Source,_size);
finally
Dest.Free;
end;
end;
finally
Source.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateFileExample('C:\1.txt',['C:\11.txt','C:\12.txt','C:\13.txt']);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
GetFileExample('c:\1.txt','c:\',1);
end;
brother (2009-05-18 07:10:00) [17]> Твой формат явно указывает колво файлов заголовком! размер
> заголовка даже при одном файле будет включать в себя еще
> 29 пустышек
это то я понял)
и
> THeader = packedrecord
смущает тк он не будет давать гарантированый размер заголовка, что имхо не есть гуд
brother (2009-05-18 07:08:00) [18]> Objs:array of TObj; - это какраз твой obj : array [1..30]
> of TObj; только в динамической реализации и вынесено из
> заголовка т.к. поле изменяемой длинны
это я понял, но я не понял откуда возьмутся записи, ведь в THeader этих записей нет значит данных вObjs:array of TObj;также нет...
Slym (2009-05-18 06:58:00) [19]brother © (18.05.09 6:15) [16]
brother © (15.05.09 9:26) [7]
THeader = record
caption:string[10];
version:string[3];
size : longword ; // размер Header
maxobj : integer; // всего добавлено файлов
obj : array [1..30] of TObj;
end;
Твой формат явно указывает колво файлов заголовком! размер заголовка даже при одном файле будет включать в себя еще 29 пустышек
Slym © (15.05.09 10:52) [14]
THeader = packed record
caption:string[10];
version:string[3];
size : longword ; // размер Header
maxobj : integer; // всего добавлено файлов
end;
мой заголовок будет работать при колве файлов от нуля до MaxInt
size : longword ; - вообще лишнее так как избыточно и ни на что не влияет при моем подходе
Objs:array of TObj; - это какраз твой obj : array [1..30] of TObj; только в динамической реализации и вынесено из заголовка т.к. поле изменяемой длинны
при доступе к файлу считывается заголовок, анализируется колво файлов и все хедеры файлов вычитываются в массив
можно не читать все хедеры а прыгнуть по индексу и читатьт только нужный хедер файла как в Slym © (15.05.09 10:58) [15]
brother © (18.05.09 6:15) [16]
? ведь инфу я и записываю и считываю, а этот вариант только для чтения?
написать запись чуть сложнее, но не намного...
основная сложность в дозаписи и перезаписифайла с изменением длинны:
нужно сдвигать фсе остальные данные но это не принципиальная сложность
нужно
brother (2009-05-18 06:15:00) [20]на [14] остановлюсь, но почему
> Objs:array of TObj;
вынес из
> THeader
? ведь инфу я и записываю и считываю, а этот вариант только для чтения?