Форум: "Начинающим";
Текущий архив: 2009.07.05;
Скачать: [xml.tar.bz2];
Внизне верное копирование файла через BlockWrite/BlockRead Найти похожие ветки
← →
brother © (2009-05-15 08:52) [0]Доброго времени суток!
Суть вот в чем:
Есть файл, из него читаю нужный объем байт и записываю в другой файл, код (черновой):
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.
не понимаю где я ошибаюсь?
← →
Palladin © (2009-05-15 08:53) [1]
> or (NumWritten <> NumRead);
это условие - ошибочно
← →
Anatoly Podgoretsky © (2009-05-15 09:11) [2]Наверно здесь
> seek(FromF, header.obj[spinedit1.Value]._seek);
← →
brother © (2009-05-15 09:11) [3]> это условие - ошибочно
все верно, по этому, я в конце копирую не весь буфер а только count-header.obj[spinedit1.Value]._size те 1000 байт и потом это является признаком выхода из цикла
← →
brother © (2009-05-15 09:12) [4]> Наверно здесь
>
> > seek(FromF, header.obj[spinedit1.Value]._seek);
нет, заголовок то файла правильный, я проверил
← →
Anatoly Podgoretsky © (2009-05-15 09:19) [5]Может и так, но нам то это неизвестно, особенно структура header.
Кстати и выбор цикла неверный, нужен while
И весь алгоритм вызывает какое то сопротивление, вместо простого и понятного, запутаный.
← →
Smile (2009-05-15 09:21) [6]> brother © (15.05.09 08:52)
Что из себя представляют ToF и FromF?Textfile, File
или еще что-то?
← →
brother © (2009-05-15 09:26) [7]> Что из себя представляют ToF и FromF?
FromF, ToF: file;
> структура header.
TObj = record
_shortname : string[100]; // имя файла без путей
_size : longword ; // размер файла
_seek : longword ; // смещение относительно начала файла
end;
THeader = record
caption:string[10];
version:string[3];
size : longword ; // размер Header
maxobj : integer; // всего добавлено файлов
obj : array [1..30] of TObj;
end;
← →
brother © (2009-05-15 09:27) [8]структура исходного файла:
заголовок (header)
файл1
файл2
файл N
← →
Smile (2009-05-15 09:43) [9]> brother ©
Структура понятна, но все-таки приведи (выложи) сюда 100 - 150 байт файла c:\1.txt
← →
brother © (2009-05-15 09:48) [10]> сюда 100 - 150 байт файла c:\1.txt
в первых 3384 байтах этого файла находится Header, и он корректно считывается
← →
brother © (2009-05-15 09:50) [11]> c:\1.txt
зы, он НЕ текстовый, это для отладки
← →
Smile (2009-05-15 10:00) [12]> brother © (15.05.09 09:50) [11]
понятно
← →
Slym © (2009-05-15 10:51) [13]var
Source,Dest:TFileStream;
Header:THeader;
Objs:array of TObj;
i:integer;
begin
Source:=TFileStream.Create("c:\1.txt",fmOpenRead);
try
Source.ReadBuffer(Header,SizeOf(Header));
SetLength(Objs,Header.maxobj);
for i:=0 to Header.maxobj do
Source.ReadBuffer(objs[i],SizeOf(TObj));
with Objs[1{spinedit1.Value}] do
begin
if Source.Seek(_seek+_size,soBeginning)<>_seek then raise Exception.Create("bad file");
if Source.Seek(_seek,soBeginning)<>_seek then raise Exception.Create("bad file");
Dest:=TFileStream.Create("c:\"+_shortname,fmCreate);
try
Dest.CopyFrom(Source,_size);
finally
Dest.Free;
end;
end;
finally
Source.Free;
end;
end;
← →
Slym © (2009-05-15 10:52) [14]упс криво...
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 TForm1.FormCreate(Sender: TObject);
var
Source,Dest:TFileStream;
Header:THeader;
Objs:array of TObj;
i:integer;
begin
Source:=TFileStream.Create("c:\1.txt",fmOpenRead);
try
Source.ReadBuffer(Header,SizeOf(Header));
SetLength(Objs,Header.maxobj);
for i:=0 to Header.maxobj do
Source.ReadBuffer(objs[i],SizeOf(TObj));
with Objs[1{spinedit1.Value}] do
begin
if Source.Seek(_seek+_size,soBeginning)<>_seek then raise Exception.Create("bad file");
if Source.Seek(_seek,soBeginning)<>_seek then raise Exception.Create("bad file");
Dest:=TFileStream.Create("c:\"+_shortname,fmCreate);
try
Dest.CopyFrom(Source,_size);
finally
Dest.Free;
end;
end;
finally
Source.Free;
end;
end;
← →
Slym © (2009-05-15 10:58) [15]или можно так:
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
← →
brother © (2009-05-18 06:15) [16]на [14] остановлюсь, но почему
> Objs:array of TObj;
вынес из
> THeader
? ведь инфу я и записываю и считываю, а этот вариант только для чтения?
← →
Slym © (2009-05-18 06:58) [17]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 07:08) [18]> Objs:array of TObj; - это какраз твой obj : array [1..30]
> of TObj; только в динамической реализации и вынесено из
> заголовка т.к. поле изменяемой длинны
это я понял, но я не понял откуда возьмутся записи, ведь в THeader этих записей нет значит данных вObjs:array of TObj;
также нет...
← →
brother © (2009-05-18 07:10) [19]> Твой формат явно указывает колво файлов заголовком! размер
> заголовка даже при одном файле будет включать в себя еще
> 29 пустышек
это то я понял)
и
> THeader = packed record
смущает тк он не будет давать гарантированый размер заголовка, что имхо не есть гуд
← →
Slym © (2009-05-18 07:36) [20]код записи без дозаписи/перезаписи
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;
← →
Slym © (2009-05-18 07:37) [21]brother © (18.05.09 7:10) [19]
как раз гарантированный размер! игнорируя алигны полей
← →
brother © (2009-05-18 07:56) [22]> 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 итд? ты же вроде как эти данные даж не записывал?
← →
brother © (2009-05-18 07:58) [23]
THeader = record
caption:string[10];
version:string[3];
size : longword ; // размер Header
maxobj : integer; // всего добавлено файлов
obj : array [1..30] of TObj;
end;
я их специально в хедер поместил, чтобы прочитав хедер, знать и размер и смещения и шортимя...
← →
Slym © (2009-05-18 08:07) [24]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 08:09) [25]> так убери... мой пример приведен для убранного...
я убрал конечно, ошибка: Cannot create file c:\абракадабра...
> Source.ReadBuffer(Obj,SizeOf(Obj));
прилетает мусор
← →
Slym © (2009-05-18 08:12) [26]packed record?
← →
Slym © (2009-05-18 08:17) [27]файл записанный моим кодом прекрасно читается моим же способом
← →
brother © (2009-05-18 08:26) [28]> файл записанный моим кодом прекрасно читается моим же способом
да все ок...
← →
brother © (2009-05-18 08:34) [29]> procedure GetFileExample(const SourceFileName,DestDir:string;
> const FileIndex:integer);
только ты его не используешь, и несмторя на:
> GetFileExample("c:\1.txt","c:\",1);
грузишь последний добавленый файл)
← →
Slym © (2009-05-18 09:15) [30]
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 09:27) [31]да поправил уже спасибо!
зы Offset:=SizeOf(Header)+(FileIndex-1)*SizeOf(TObj2); ;))))
← →
Slym © (2009-05-18 09:31) [32]brother © (18.05.09 9:27) [31]
FileIndex-1
Зочем? принято нумеровать от нуля...
← →
brother © (2009-05-18 09:47) [33]> Зочем? принято нумеровать от нуля...
чтоб спинедит не корректировать
← →
Slym © (2009-05-18 09:53) [34]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:57) [35]> и кошернее обернуть все это в объектную оболочку
подумаю, о кошерности) спасибо!
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2009.07.05;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.005 c