将文件拆分为TFileStream

时间:2016-09-21 17:45:53

标签: delphi

我正在做两个函数来加入和分割TFileStream中的文件,代码:

加入

procedure TFormHome.btnJoinClick(Sender: TObject);
var
  InStream, OutStream: TFileStream;
  OutFileName, InFileName1, InFileName2: string;
begin
  OutFileName := 'salida.out';
  InFileName1 := 'image.jpg';
  InFileName2 := 'test.exe';
  OutStream := TFileStream.Create(OutFileName, fmCreate);
  try
    InStream := TFileStream.Create(InFileName1, fmOpenRead);
    ShowMessage(IntToStr(InStream.Size));
    try
      OutStream.CopyFrom(InStream, InStream.Size);
    finally
      InStream.Free;
    end;
    InStream := TFileStream.Create(InFileName2, fmOpenRead);
    ShowMessage(IntToStr(InStream.Size));
    try
      OutStream.CopyFrom(InStream, InStream.Size);
    finally
      InStream.Free;
    end;
  finally
    OutStream.Free;
  end;
end;

鸿沟

procedure TFormHome.btnUnJoinClick(Sender: TObject);
var
  Source, Target: TStream;
  Buffer: array of Byte;
  i: Integer;
  SourceName, TargetNames: string;
  SizeTargets: Integer;
begin
  SourceName := 'salida.out';
  TargetNames := 'test.exe';
  SizeTargets := 2232832;
  Source := TFileStream.Create(SourceName, fmOpenRead);
  Target := TFileStream.Create(TargetNames, fmCreate);
  try
    SetLength(Buffer, SizeTargets);
    Source.ReadBuffer(Pointer(Buffer)^, Length(Buffer));
    Target.WriteBuffer(Buffer[0], Length(Buffer));
  finally
    Target.Free;
  end;
end;

问题在于,当我分割文件时,可执行文件在我想显示错误时会中断并运行:

  Windows can not find the file "route ..." Make sure the name is spelled correctly and try again

  The version of this file is not compatible with the version of Windows you are running ... (and then talking about 32 or 64 bits)

同时检查第二个函数中可执行文件的大小是否正常。

问题在于,在第二个代码中,所有文件都被破坏了

如何解决这个问题?

1 个答案:

答案 0 :(得分:4)

您正在连接多个输入文件,而不在输出中指示一个文件结束而下一个文件开始。您的除法码不知道哪些字节属于JPG,哪些字节属于EXE。

例如,您显示的除法代码是提取JPG字节并将其保存到.exe文件。当然,.exe文件无法正常运行。

为了提取EXE,您必须首先提取/跳过JPG,这意味着您必须知道JPG中有多少字节。因此,您需要将输入文件大小存储在连接的输出中,而不仅仅是它们的数据,例如:

procedure TFormHome.btnJoinClick(Sender: TObject);
var
  OutStream: TFileStream;

  procedure AddFile(const FileName: sstring);
  var
    InStream: TStream;
    Size: Int64;
  begin
    InStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    try
      Size := InStream.Size;
      OutStream.WriteBuffer(Size, SizeOf(Size));
      OutStream.CopyFrom(InStream, Size);
    finally
      InStream.Free;
    end;
  end;

begin
  OutStream := TFileStream.Create('salida.out', fmCreate);
  try
    AddFile('image.jpg');
    AddFile('test.exe');
  finally
    OutStream.Free;
  end;
end;

procedure TFormHome.btnUnJoinClick(Sender: TObject);
var
  Source: TStream;

  procedure SkipFile;
  var
    Size: Int64;
  begin
    Source.ReadBuffer(Size, SizeOf(Size));
    Source.Seek(Size, soCurrent);
  end;

  procedure ExtractFile(const FileName: string);
  var
    Target: TStream;
    Size: Int64;
  begin
    Source.ReadBuffer(Size, SizeOf(Size));

    Target := TFileStream.Create(FileName, fmCreate);
    try
      Target.CopyFrom(Source, Size);
    finally
      Target.Free;
    end;
  end;

begin
  Source := TFileStream.Create('salida.out', fmOpenRead or fmShareDenyWrite);
  try
    SkipFile;
    ExtractFile('test.exe');
  finally
    Source.Free;
  end;
end;

我建议您考虑存储文件名:

procedure TFormHome.btnJoinClick(Sender: TObject);
var
  OutStream: TFileStream;

  procedure AddFile(const FileName: string);
  var
    InStream: TStream;
    Name: UTF8String;
    Len: Integer;
    FileSize, TotalSize: Int64;
  begin
    InStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
    try
      Name := UTF8String(ExtractFileName(FileName));
      Len := Length(Name);

      FileSize := InStream.Size;

      TotalSize := SizeOf(Len) + Len + SizeOf(FileSize) + FileSize;
      OutStream.WriteBuffer(TotalSize, SizeOf(TotalSize));

      OutStream.WriteBuffer(Len, SizeOf(Len));
      OutStream.WriteBuffer(PAnsiChar(Name)^, Len);
      OutStream.WriteBuffer(FileSize, SizeOf(FileSize));
      OutStream.CopyFrom(InStream, FileSize);
    finally
      InStream.Free;
    end;
  end;

begin
  OutStream := TFileStream.Create('salida.out', fmCreate);
  try
    AddFile('image.jpg');
    AddFile('test.exe');
  finally
    OutStream.Free;
  end;
end;

procedure TFormHome.btnUnJoinClick(Sender: TObject);
var
  Source: TStream;

  procedure SkipFile;
  var
    TotalSize: Int64;
  begin
    Source.ReadBuffer(TotalSize, SizeOf(TotalSize));
    Source.Seek(TotalSize, soCurrent);
  end;

  procedure ExtractFile;
  var
    Target: TStream;
    TotalSize, FileSize: Int64;
    Name: UTF8String;
    Len: Integer;
    Pos: Int64;
  begin
    Source.ReadBuffer(TotalSize, SizeOf(TotalSize));
    Pos := Source.Position;

    Source.ReadBuffer(Len, SizeOf(Len));
    SetLength(Name, Len);
    Source.ReadBuffer(PAnsiChar(Name)^, Len);

    Source.ReadBuffer(FileSize, SizeOf(FileSize));

    Target := TFileStream.Create(String(Name), fmCreate);
    try
      Target.CopyFrom(Source, FileSize);
    finally
      Target.Free;
    end;

    if (Source.Position - Pos) <> TotalSize then
      raise Exception.Create('Extract failed. Bad position');
  end;

begin
  Source := TFileStream.Create('salida.out', fmOpenRead or fmShareDenyWrite);
  try
    SkipFile;
    ExtractFile;
  finally
    Source.Free;
  end;
end;