Форум: "Начинающим";
Текущий архив: 2008.11.23;
Скачать: [xml.tar.bz2];
ВнизПроблема с распаковкой архива Найти похожие ветки
← →
Vayrus (2008-10-13 00:01) [0]Доброго времени суток уважаемые.
Следующие строчки кода предназначены для склейки/разбивки файлов:
unit SJS;
interface
uses
Windows, FS, Classes, SAPIF, dialogs,messages;
const
Signature = "SLA!";
Author = "Vayrus";
Version = "1.0";
type
TArcHead = packed record
Sign : array[0..3] of char;
Vers : String[4];
Auth : array[0..11] of char;
Comm : String;
end;
type
TFileHead = packed record
FN : ShortString;//Oieuei oae
FSize : Longint;
end;
Type
TActionFuntion = function(InStream, OutStream: TStream): Boolean;
TOperationCallBack = procedure(CurFile: String; OverallMax, OverallPosition: Integer);
var
STOP: Boolean = False;
procedure JoinToOne(Files: TStrings; const FileName: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
procedure SplitToDir(const FileName, DestDirectory: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
implementation
function GetFilesSize(InFiles: TStrings): Integer;
var
I : Integer;
begin
RESULT := 0;
For I := 0 To InFiles.Count - 1 do
begin
RESULT := RESULT + _GetFileSize(InFiles[I]);
ProcessMessages;
end;
end;
procedure JoinToOne(Files: TStrings; const FileName: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
var
InFile, OutFile : TFileStream;
Tmp : TMemoryStream;
I : Integer;
AllSize, CurPos : Integer;
ArcHead : TArcHead;
FileHead : TFileHead;
begin
STOP := False;
CurPos := 0;
if Files.Count = 0 then EXIT;//
AllSize := GetFilesSize(Files) - SizeOf(TArcHead);//
OutFile := TFileStream.Create(FileName, fmCreate);
try
with ArcHead do
begin
Sign := Signature;
Vers := Version;
Auth := Author;
Comm := "oano";
end;
OutFile.Write(ArcHead, SizeOf(TArcHead));
for I := 0 to Files.Count - 1 do
begin
InFile := TFileStream.Create(Files[I], fmOpenRead);
try
Tmp := TMemoryStream.Create;
try
if not ActFunc(InFile, Tmp) then
begin
OutFile.Free;
InFile.Free;
Tmp.Free;
EXIT;
end;
with FileHead do
begin
FN := ExtractFileName(Files[I]);
FSize := Tmp.Size;
end;
Outfile.Write(FileHead, SizeOf(TFileHead));
OutFile.CopyFrom(Tmp, 0);
//
CurPos := CurPos + InFile.Size + SizeOf(TFileHead);//
Progress(Files[I], AllSize, CurPos);
//
finally
InFile.Free;
end;
finally
Tmp.Free;
end;
if STOP then BREAK;
ProcessMessages;
end;
finally
OutFile.Free;
end;
if STOP then DeleteFile(PChar(FileName));//
end;
procedure SplitToDir(const FileName, DestDirectory: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
var
Dest : String;
InFile, OutFile : TFilestream;
Tmp : TMemoryStream;
AllSize, CurPos : Integer;
ArcHead : TArcHead;
FileHead : TFileHead;
begin
STOP := False;//
CurPos := 0;//
if not DirectoryExists(DestDirectory) then EXIT;//
Dest := IncludeTrailingPathDelimiter(DestDirectory);//
InFile := TFileStream.Create(FileName, fmOpenRead);
try
AllSize := InFile.Size - SizeOf(TArcHead);//
//InFile.Seek(0, soFromBeginning);
InFile.Read(ArcHead, SizeOf(TArcHead));
if ArcHead.Sign <> Signature then
if MessageBox(0, "Oi?iao oaeea ia iiaaa??eaaaony, ?aniaeiaaou i?eioaeoaeuii?", "Ioeaea", MB_YESNO or MB_ICONERROR) <> IDYES then
begin
InFile.Free;
EXIT;
end;
while InFile.Position <> InFile.Size do
begin
InFile.Read(FileHead, SizeOf(TFileHead));
OutFile := TFileStream.Create(Dest + FileHead.FN, fmCreate);
try
Tmp := TMemoryStream.Create;
try
Tmp.CopyFrom(InFile, FileHead.FSize);
if not ActFunc(Tmp, OutFile) then
begin
InFile.Free;
OutFile.Free;
Tmp.Free;
EXIT;
end;
//OutFile.CopyFrom(Tmp2, Tmp2.Size);
//
CurPos := CurPos + FileHead.FSize + SizeOf(TFileHead);//
Progress(Dest + FileHead.FN, AllSize, CurPos);
//
finally
OutFile.Free;
end;
finally
Tmp.Free;
end;
if STOP then BREAK;
ProcessMessages;
end;
finally
InFile.Free;
end;
end;
end.
Подскажите, пожалуйста, правильный код распаковки. Упаковка отрабатывает хорошо, но вот не пойму почему распаковка не работает (вылетает ошибув чтения потока).
← →
Германн © (2008-10-13 00:24) [1]Comm : String;
Какая нафиг длинная строка в записи?
← →
KilkennyCat © (2008-10-13 00:38) [2]
> Германн © (13.10.08 00:24) [1]
теоретически можно.
← →
Германн © (2008-10-13 00:49) [3]
> KilkennyCat © (13.10.08 00:38) [2]
>
>
> > Германн © (13.10.08 00:24) [1]
>
> теоретически можно.
>
Что можно? Вот это можно:
> InFile.Read(ArcHead, SizeOf(TArcHead));
?
← →
KilkennyCat © (2008-10-13 01:27) [4]в данном случае - нет.
← →
Германн © (2008-10-13 01:38) [5]
> KilkennyCat © (13.10.08 01:27) [4]
>
> в данном случае - нет.
>
Ну и я о том же. Но автор молчит. Смущает то, что все прочие строковые элементы записей явно обозначены как короткие строки. То ли очепятка при переносе кода на форум, то ли собственные изменения надыбанного где-то кода без ясного понимания.
P.S. Судя по интерфейсному юзесу, скорее второе :)
← →
KilkennyCat © (2008-10-13 01:45) [6]
> скорее второе
плюс еще почему-то разномастное
> TArcHead = packed record
> Sign : array[0..3] of char;
> Vers : String[4];
> Auth : array[0..11] of char;
> Comm : String;
и несовпадение размеров с
> const
> Signature = "SLA!";
> Author = "Vayrus";
> Version = "1.0";
что в дальнейшем тож может вызвать проблемы.
← →
Германн © (2008-10-13 01:59) [7]
> KilkennyCat © (13.10.08 01:45) [6]
> и несовпадение размеров с
>
> > const
> > Signature = "SLA!";
> > Author = "Vayrus";
> > Version = "1.0";
>
> что в дальнейшем тож может вызвать проблемы.
>
Не. Это не вызовет проблем. Ведь в случае короткой строки в записи будет присутствовать явно нулевой символ короткой строки. И несовпадение размеров может быть только при превышении.
← →
KilkennyCat © (2008-10-13 02:20) [8]Все зависит от дальнейшего решения.
← →
Германн © (2008-10-13 02:26) [9]
> KilkennyCat © (13.10.08 02:20) [8]
>
> Все зависит от дальнейшего решения.
>
Автор задал вопрос. Ему ответили. Без его участия считаю топик мёртвым.
← →
Vayrus (2008-10-13 12:19) [10]Спасибо за участие, код мой, в архивации и описании типов не силен, проблему решил - нехватало одной строчки (Tmp.Seek(0, soFromBeginning)), вот полный код:
procedure SplitToDir(const FileName, DestDirectory: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
var
Dest : String;
InFile, OutFile : TFilestream;
AllSize, CurPos : Integer;
ArcHead:TArcHead;
FileHead:TFileHead;
Tmp:TMemoryStream;
begin
STOP := False;//
CurPos := 0;//
if not DirectoryExists(DestDirectory) then EXIT;//
Dest := IncludeTrailingPathDelimiter(DestDirectory);//
InFile := TFileStream.Create(FileName, fmOpenRead);
try
AllSize := InFile.Size - SizeOf(TArcHead);//
InFile.Read(ArcHead,sizeof(TArcHead));
if ArcHead.Sign <> Signature then
if MessageBox(0, "Формат файла не поддерживается, распаковать принудительно?", "Ошибка", MB_YESNO or MB_ICONERROR) <> IDYES then EXIT;
while InFile.Position <> InFile.Size do //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
begin
InFile.Read(FileHead,sizeof(TFileHead));
OutFile := TFileStream.Create(Dest+FileHead.FN, fmCreate);
//
Tmp:=TMemoryStream.Create;
try
Tmp.CopyFrom(InFile, FileHead.FSize);
Tmp.Seek(0, soFromBeginning);//Обязательно
if not ActFunc(Tmp, OutFile) then
begin
InFile.Free;
OutFile.Free;
Tmp.Free;
EXIT;
end;
//
CurPos := CurPos + FileHead.FSize + SizeOf(TFileHead);//
Progress(Dest + FileHead.FN, AllSize, CurPos);
//
OutFile.Free;
finally
Tmp.Free;
end;
ProcessMessages;
end;
finally
InFile.Free;
end;
end;
Раз уж я неправильно описал типы, то представьте мне правильный вариант.
← →
Vayrus (2008-10-13 12:30) [11]Как я понял, описание типов должно иметь примерно следующий вид:
type
TArcHead = packed record
Sign : String[4];
Vers : String[3];
Auth : String[12];
Comm : String[60];
end;
type
TFileHead = packed record
FN : ShortString;//Oieuei oae
FSize : Longint;
end;
← →
Vayrus (2008-10-13 12:42) [12]Вот окончательный мой вариант:
type
TArcHead = packed record
Sign : String[4];
Vers : String[4];
Auth : String[12];
Comm : String[100];
end;
type
TFileHead = packed record
FN : String[100];//Только так
FSize : Longint;
end;
← →
KilkennyCat © (2008-10-13 12:43) [13]
> FN : String[100];//Только так
почему только так? ShortString тоже имеет фиксированный размер.
← →
Vayrus (2008-10-13 13:39) [14]
> почему только так? ShortString тоже имеет фиксированный
> размер.
Нет, это лично пометка для себя, старая, забыл убрать, не обращайте на это внимания.
← →
Ega23 © (2008-10-13 13:46) [15]
> while InFile.Position <> InFile.Size do
Строго меньше.
← →
Vayrus (2008-10-13 13:46) [16]Теперь, надеюсь, правильно:
type
TArcHead = packed record
Sign : String[4];
Vers : String[4];
Auth : String[12];
Comm : ShortString;
end;
type
TFileHead = packed record
FN : ShortString;
FSize : Longint;
end;
А как увеличить отводимую под комментарий строку и можно ли использовать WideString для комментария и имен файлов ?
← →
Vayrus (2008-10-13 13:47) [17]
> Строго меньше.
Учту, спасибо.
← →
Ega23 © (2008-10-13 14:00) [18]
> А как увеличить отводимую под комментарий строку и можно
> ли использовать WideString для комментария и имен файлов
> ?
Использовать стринг можно. Но аккуратно. Что-то типа:type
TBlockHeader = packed record
BlockID : Integer;
BlockSize : Integer;
end;
А дальше всё тупо. Есть сущность "Комментарий". Заводим на неё в некоем "реестре" константу с кодом её блока. Например - cComment = $1F00;
Теперь, когда надо строку записать, причём именно как комментарий -
procedure StreamWriteString(Stream : TStream; const Value : string;
const BlockID : Cardinal);
var
BlockSize : Cardinal;
begin
BlockSize := Length(Value);
Stream.WriteBuffer(BlockID, 4);
Stream.WriteBuffer(BlockSize, 4);
Stream.WriteBuffer(PChar(Value)^, BlockSize);
end;
← →
Vayrus (2008-10-13 14:48) [19]
> Использовать стринг можно. Но аккуратно. Что-то типа
Если Я Вас правильно понял, то получается примерно следующее:unit SJS;
interface
uses
Windows, FS, Classes, SAPIF, dialogs,messages;
const
Signature = "SLA!";
Author = "Vayrus";
Version = "1.0";
CommID = $1F00;
type
TArcHead = packed record
Sign : String[4];
Vers : String[4];
Auth : String[12];
// Comm : ShortString;
end;
type
TFileHead = packed record
FN : ShortString;
FSize : Longint;
end;
type
TBlockHeader = packed record
BlockID : Integer;
BlockSize : Integer;
end;
Type
TActionFuntion = function(InStream, OutStream: TStream): Boolean;
TOperationCallBack = procedure(CurFile: String; OverallMax, OverallPosition: Integer);
var
STOP: Boolean = False;
procedure JoinToOne(Files: TStrings; const FileName: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
procedure SplitToDir(const FileName, DestDirectory: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
implementation
procedure StreamWriteString(Stream : TStream; const Value : String;
const BlockID : Cardinal);
var
BlockSize : Cardinal;
begin
BlockSize := Length(Value);
Stream.WriteBuffer(BlockID, 4);
Stream.WriteBuffer(BlockSize, 4);
Stream.WriteBuffer(PChar(Value)^, BlockSize);
end;
function StreamReadString(Stream : TStream;
const BlockID, BlockSize : Cardinal): String;
var
M: TStringStream;
begin
M := TStringStream.Create("");
try
M.CopyFrom(Stream, BlockSize);
RESULT := M.DataString;
finally
M.Free;
end;
end;
function GetFilesSize(InFiles: TStrings): Integer;
var
I : Integer;
begin
RESULT := 0;
For I := 0 To InFiles.Count - 1 do
begin
RESULT := RESULT + _GetFileSize(InFiles[I]);
ProcessMessages;
end;
end;
procedure JoinToOne(Files: TStrings; const FileName: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
var
InFile, OutFile : TFileStream;
Tmp : TMemoryStream;
I : Integer;
AllSize, CurPos : Integer;
ArcHead : TArcHead;
FileHead : TFileHead;
begin
STOP := False;
CurPos := 0;
if Files.Count = 0 then EXIT;//
AllSize := GetFilesSize(Files) - SizeOf(TArcHead);//
OutFile := TFileStream.Create(FileName, fmCreate);
try
with ArcHead do
begin
Sign := Signature;
Vers := Version;
Auth := Author;
//Comm := "òåñò";
end;
OutFile.Write(ArcHead, SizeOf(TArcHead));
//
StreamWriteString(OutFile,
WideString("Íà÷àëî Ñòðîêè -> ... -> Êîíåö Ñòðîêè"),
CommID);
//
for I := 0 to Files.Count - 1 do
begin
InFile := TFileStream.Create(Files[I], fmOpenRead);
try
Tmp := TMemoryStream.Create;
try
if not ActFunc(InFile, Tmp) then
begin
OutFile.Free;
InFile.Free;
Tmp.Free;
EXIT;
end;
with FileHead do
begin
FN := ExtractFileName(Files[I]);
FSize := Tmp.Size;
end;
Outfile.Write(FileHead, SizeOf(TFileHead));
OutFile.CopyFrom(Tmp, 0);
//
CurPos := CurPos + InFile.Size + SizeOf(TFileHead);//
Progress(Files[I], AllSize, CurPos);
//
finally
Tmp.Free;
end;
finally
InFile.Free;
end;
if STOP then BREAK;
ProcessMessages;
end;
finally
OutFile.Free;
end;
if STOP then DeleteFile(PChar(FileName));//
end;
procedure SplitToDir(const FileName, DestDirectory: String; ActFunc :TActionFuntion; Progress: TOperationCallBack);
var
Dest : String;
InFile, OutFile : TFilestream;
AllSize, CurPos : Integer;
ArcHead:TArcHead;
FileHead:TFileHead;
Tmp:TMemoryStream;
BlockHead:TBlockHeader;
begin
STOP := False;//
CurPos := 0;//
if not DirectoryExists(DestDirectory) then EXIT;//
Dest := IncludeTrailingPathDelimiter(DestDirectory);//
InFile := TFileStream.Create(FileName, fmOpenRead);
try
AllSize := InFile.Size - SizeOf(TArcHead);//
InFile.Read(ArcHead,sizeof(TArcHead));
if ArcHead.Sign <> Signature then
if MessageBox(0, "Ôîðìàò ôàéëà íå ïîääåðæèâàåòñ&# 255;, ðàñïàêîâàòü ïðèíóäèòåëüíî?" , "Îøèáêà", MB_YESNO or MB_ICONERROR) <> IDYES then EXIT;
//
InFile.Read(BlockHead, SizeOf(TBlockHeader));
ShowMessage(StreamReadString(InFile, BlockHead.BlockID, BlockHead.BlockSize));
//
while InFile.Position < InFile.Size do //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
begin
InFile.Read(FileHead,sizeof(TFileHead));
OutFile := TFileStream.Create(Dest+FileHead.FN, fmCreate);
//
Tmp:=TMemoryStream.Create;
try
Tmp.CopyFrom(InFile, FileHead.FSize);
Tmp.Seek(0, soFromBeginning);//Îáÿçàòåëüíî
if not ActFunc(Tmp, OutFile) then
begin
InFile.Free;
OutFile.Free;
Tmp.Free;
EXIT;
end;
//
CurPos := CurPos + FileHead.FSize + SizeOf(TFileHead);//
Progress(Dest + FileHead.FN, AllSize, CurPos);
//
OutFile.Free;
finally
Tmp.Free;
end;
ProcessMessages;
end;
finally
InFile.Free;
end;
end;
end.
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2008.11.23;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.006 c