Juntar 2 arquivos num só

Delphi

31/01/2004

Gostária de saber se tem como juntar 2 arquivos em um só. Por exemplo, eu fiz um ´instalador´ usando um componente de zip, ... E neste .exe que eu fiz, gostária que ele armazenasse também o ZIP e virasse um arquivo só, tem como?


Doctor-x

Doctor-x

Curtidas 0

Respostas

Beppe

Beppe

31/01/2004

procedure MergeFiles(const Dest: String; const Sources: array of String);
var
  I, Len: Integer;
  Output, Src: TStream;
begin
  Output := TFileStream.Create(Dest, fmCreate);
  try
    for I := 0 to High(Sources) do
    begin
      // escreve o nome do arquivo, prefixado com o tamanho do nome
      Len := Length(Sources[I]);
      Output.Write(Len, SizeOf(Integer));
      Output.Write(Pointer(Sources[I])^, Len);

      // copia o arquivo, prefixado com o tamanho do mesmo
      Src := TFileStream.Create(Sources[I], fmOpenRead or fmShareDenyWrite);
      try
        Len := Src.Size;
        Output.Write(Len, SizeOf(Integer));
        Output.CopyFrom(Src, Len);
      finally
        Src.Free;
      end;
    end;
  finally
    Output.Free;
  end;
end;

procedure ExtractFiles(const Filename: String);
var
  I, Len: Integer;
  Output, Src: TStream;
  Name: String;
begin
  Src := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
  try
    while Src.Size > Src.Position do
    begin
      Src.ReadBuffer(Len, SizeOf(Integer));
      SetLength(Name, Len);
      Output.ReadBuffer(Pointer(Name)^, Len);

      Output := TFileStream.Create(Name, fmCreate);
      try
        Src.ReadBuffer(Len, SizeOf(Integer));
        Output.CopyFrom(Src, Len);
      finally
        Output.Free;
      end;
    end;
  finally
    Src.Free;
  end;
end;


Eu acabei escrevendo isto(não testei), mas depois vi que sua duvida pode ser outra. O que você quer é fazer um auto-extract?

Se é juntar dois arquivos, o código é esse. Chama assim:

// juntando os arquivos
MergeFiles(´dest.dst´, [´source1.exe´, ´source2.zip´]);
// extrai os arquivos
ExtractFiles(´dest.dst´);



GOSTEI 0
Doctor-x

Doctor-x

31/01/2004

procedure MergeFiles(const Dest: String; const Sources: array of String);
var
  I, Len: Integer;
  Output, Src: TStream;
begin
  Output := TFileStream.Create(Dest, fmCreate);
  try
    for I := 0 to High(Sources) do

ExtractFiles(´dest.dst´);


Vou explicar, é mais ou menos assim: Eu criei um arquivo.zip e um executavel. No executavel eu uso um componente para descompactação de arquivos. Então eu queria um modo de este arquivo .zip e o .exe que eu criei ser um arquivo só .exe tipo um auto-extrator mesmo, mas eu não queria que ficasse o .exe e o .zip, e sim um jeito de ´colocar´ o .zip dentro do .exe para ter somente 1 arquivo


GOSTEI 0
Beppe

Beppe

31/01/2004

O seu componente de zipar já não faz isso? Tem alguns que fazem...

Mas tem sim como. Você cria um executável que extrai os dados compactados em um recurso. Aí tem duas opções de fazer isso: ou você gera o executável, seção por seção, coloca o recurso e o código de extração(x86), ou você cria no Delphi um executável(o auto-extract) que faça isso. Então no seu programa você coloca o .zip como recurso no executável auto-extract através da API do Windows.

Mas dá uma olhada que tem componentes que fazem isso.


GOSTEI 0
Doctor-x

Doctor-x

31/01/2004

O seu componente de zipar já não faz isso? Tem alguns que fazem... Mas tem sim como. Você cria um executável que extrai os dados compactados em um recurso. Aí tem duas opções de fazer isso: ou você gera o executável, seção por seção, coloca o recurso e o código de extração(x86), ou você cria no Delphi um executável(o auto-extract) que faça isso. Então no seu programa você coloca o .zip como recurso no executável auto-extract através da API do Windows. Mas dá uma olhada que tem componentes que fazem isso.



vocÊ poderia me dar um exemplo da segunda opção... de criar o auto-extrator usando o Delphi ... é pq o programa que eu fiz, precisa de umas configurações antes do programa rodar pela primeira vez... e eu to fazendo isso com o meu executavel. Só que no momento ele funciona com 2 arquivos, o executavel que eu fiz no Delphi e o .zip do que contém o programa... Eu gostária de ter somente o executavel do Delphi com o zip ´dentro´ dele


GOSTEI 0
Beppe

Beppe

31/01/2004

Eu posso te apontar como fazer, mas não posso te passar muito código, pois não tenho tempo(é um pouco demorado), e estou num sistema sem o SDK do Windows, e as funçãos não sei totalmente de cor.

Procedimentos:
1) Escreva e compile um programa no Delphi que faça isso:
- O seu componente de zip deve ter a opção de descompactar de uma stream para arquivo, certo? Você a usa pra pegar o recurso compactado.
Você acessa o recurso criando uma instância de TResourceStream, passando o nome do recurso. Passa entao essa stream pro zip descompactar.
2) Escreva e compile um programa no Delphi que faça isso:
Este programa gera o auto-extract. Ele pega o executável 1, abre com BeginUpdateResource, acrescenta o .zip como recurso passando um nome e tipo, depois chama EndUpdateResource.

Como disse não me lembro exato do nome das APIs, mas procura por resource na Windows.pas que tu acha algo.

Se tiver dúvidas é só falar.


GOSTEI 0
Paulocesar1301

Paulocesar1301

31/01/2004

Porque vc simplesmente não cria um .RES com o arquivo .ZIP dentro e joga dentro do seu projeto ? Usa o RCData. Qdopreciso de recursos externos uso assim e funciona blz.


GOSTEI 0
Doctor-x

Doctor-x

31/01/2004

Porque vc simplesmente não cria um .RES com o arquivo .ZIP dentro e joga dentro do seu projeto ? Usa o RCData. Qdopreciso de recursos externos uso assim e funciona blz.


você poderia me dar uma dica simples de como fazer isso?


GOSTEI 0
Beppe

Beppe

31/01/2004

Gente, conforme apontado pelo caninha51, tinha um erro numa rotina que postei, ExtractFiles. Era só um nome de parâmetro trocado. :oops:


GOSTEI 0
Caninha51

Caninha51

31/01/2004

Na verdade, ainda continua com um errinho...

Em ExtractFile, e vez de...
Output.ReadBuffer(Pointer(Name)^, Len);

Eh...
Src.ReadBuffer(Pointer(Name)^, Len);

Só confundiu as Stream´s! :))

Valew Beppe!

Caninha51


GOSTEI 0
Beppe

Beppe

31/01/2004

procedure MergeFiles(const Dest: String; const Sources: array of String);
var
  I, Len: Integer;
  Output, Src: TStream;
begin
  Output := TFileStream.Create(Dest, fmCreate);
  try
    for I := 0 to High(Sources) do
    begin
      // escreve o nome do arquivo, prefixado com o tamanho do nome
      Len := Length(Sources[I]);
      Output.Write(Len, SizeOf(Integer));
      Output.Write(Pointer(Sources[I])^, Len);

      // copia o arquivo, prefixado com o tamanho do mesmo
      Src := TFileStream.Create(Sources[I], fmOpenRead or fmShareDenyWrite);
      try
        Len := Src.Size;
        Output.Write(Len, SizeOf(Integer));
        Output.CopyFrom(Src, Len);
      finally
        Src.Free;
      end;
    end;
  finally
    Output.Free;
  end;
end;

procedure ExtractFiles(const Filename: String);
var
  I, Len: Integer;
  Output, Src: TStream;
  Name: String;
begin
  Src := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
  try
    while Src.Size > Src.Position do
    begin
      Src.ReadBuffer(Len, SizeOf(Integer));
      SetLength(Name, Len);
      Src.ReadBuffer(Pointer(Name)^, Len);

      Output := TFileStream.Create(Name, fmCreate);
      try
        Src.ReadBuffer(Len, SizeOf(Integer));
        Output.CopyFrom(Src, Len);
      finally
        Output.Free;
      end;
    end;
  finally
    Src.Free;
  end;
end;
Eu acabei escrevendo isto(não testei), mas depois vi que sua duvida pode ser outra. O que você quer é fazer um auto-extract? Se é juntar dois arquivos, o código é esse. Chama assim:
// juntando os arquivos
MergeFiles(´dest.dst´, [´source1.exe´, ´source2.zip´]);
// extrai os arquivos
ExtractFiles(´dest.dst´);



GOSTEI 0
Beppe

Beppe

31/01/2004

Na verdade, ainda continua com um errinho... Em ExtractFile, e vez de... Output.ReadBuffer(Pointer(Name)^, Len); Eh... Src.ReadBuffer(Pointer(Name)^, Len); Só confundiu as Stream´s! :)) Valew Beppe! Caninha51


Hehe, agora é um erro a menos. :wink:

PS: Continuo sem testar... :P


GOSTEI 0
Icheuk

Icheuk

31/01/2004

Beppe tudo bem, espero que sim.

Voce colou uma dica muito interessante, a de juntar dois arquivos ou seja eu tenho o meu executavel e posso juntar a ele outro arquivo qualquer certo ?

Bom a pergunta é a seguinte, eu consigo alterar este segundo arquivo, via codigo sem tira-lo do arquivo principal.

Ex. Arq1.Exe, Arq2.Txt

Fiz o merge e ficou Arq1.Exe ( porem agora o exe tem o dois arquivos.

O conteudo do arq2.Txt:

este arquivo contem a letra A.

Agora eu quero colocar a letra B.

e o arquivo ficar assim:

este arquivo contem a letra AB.

teria como fazer isto sem extrair o arquivo Txt e depois fazer o merge novamente.

Agradeço antecipadamente a ajuda.


GOSTEI 0
Beppe

Beppe

31/01/2004

teria como fazer isto sem extrair o arquivo Txt e depois fazer o merge novamente.


Não é simples como append´er esse bytes, é necessário atualizar o tamanho do arquivo também.

procedure AppendStringToSecondFile(const Filename: String; const Text: String);
var 
  I, Len: Integer; 
  Output, Src: TStream; 
  Name: String; 
begin 
  Src := TFileStream.Create(Filename, fmOpenReadWrite or fmShareDenyWrite); 
  try
    // pula o primeiro arquivo
    Src.ReadBuffer(Len, SizeOf(Integer));
    Src.Seek(Len, soFromCurrent);

    // atualiza o tamanho do segundo arquivo
    Src.ReadBuffer(Len, SizeOf(Integer));
    Src.Seek(-SizeOf(Integer), soFromCurrent);
    Inc(Len, Length(Text));
    Src.WriteBuffer(Len, SizeOf(Integer));

    // acrescenta novos dados
    Src.Seek(0, soFromEnd);
    Src.WriteBuffer(Pointer(Text)^, Length(Text));
  finally 
    Src.Free; 
  end; 
end;


PS: não testei


GOSTEI 0
Guilherme

Guilherme

31/01/2004

para juntar parece estar juntando certin mais para extrair nao estou achando para onde ele extrai os arquivos , tem como indicar um local para a extraçao ????


GOSTEI 0
Beppe

Beppe

31/01/2004

Oi.

Vou te ensinar como modificar a(s) rotina(s) para seus propósitos. Usei o caminho absoluto tanto para merge como extract. Na hora de extrair, o arquivo será criado dentro do diretório original, o que pode ou não ser o desejado. Chame ExtractFilename(Nome) para pegar apenas a porção que indica o nome relativo do arquivo, e ao criar o arquivo, ou sete o diretório corrente(SetCurrentDir) ou concatene um novo nome de diretório. Lembre-se de que o diretório já precisa estar criado, pode garantir isso com ForceDirectories(Nome).

Boa sorte.


GOSTEI 0
Andrew Vargas

Andrew Vargas

31/01/2004

Beleza Doctor-x? Você conseguiu resolver o problema? Eu tenho uma dúvida parecida, se puder dá uma olhada nesse link https://www.devmedia.com.br/forum/executar-programa-carregado-em-um-memorystream/486076

Valeu.
GOSTEI 0
Anderson Jesus

Anderson Jesus

31/01/2004

Na verdade, ainda continua com um errinho... Em ExtractFile, e vez de... Output.ReadBuffer(Pointer(Name)^, Len); Eh... Src.ReadBuffer(Pointer(Name)^, Len); Só confundiu as Stream´s! :)) Valew Beppe! Caninha51


Hehe, agora é um erro a menos. :wink:

PS: Continuo sem testar... :P




Olá, precisei fazer um merge dos xml originados do ClientDataSet e acabei apanhando bastante da rotina (Deve ser por conta do Windows 10), pois o nome do arquivo nunca era salvo corretamente dentro do arquivo de destino. (Geralmente gravava lixo de memória ou metade do nome). Depois de muito estudar e ter que aprender ponteiros (Principalmente na parte que ensina como as Strings são controladas em https://www.devmedia.com.br/ponteiros-clube-delphi-118/17178) consegui entender o problema e fiz algumas alterações na rotina para salvar sem o diretório do arquivo e com a alteração de String para AnsiString .
Caso alguém precise:


procedure TfrmPediEsto.MergeFiles(const Dest: String;
  const Sources: array of String);
var
  I, Len: Integer;
  Output, Src: TStream;
  ls_Arq : AnsiString;

begin
  Output := TFileStream.Create(Dest, fmCreate);
  try
    for I := 0 to High(Sources) do
    begin
      // escreve o nome do arquivo, prefixado com o tamanho do nome
      ls_Arq := ExtractFileName(Sources[I]);
      Len := Length(ls_Arq);
      Output.Write(Len, SizeOf(Integer));
      Output.Write(PAnsiString(ls_Arq)^, Len);
      // copia o arquivo, prefixado com o tamanho do mesmo
      Src := TFileStream.Create(Sources[I], fmOpenRead or fmShareDenyWrite);
      try
        Len := Src.Size;
        Output.Write(Len, SizeOf(Integer));
        Output.CopyFrom(Src, Len);
      finally
        Src.Free;
      end;
    end;
  finally
    Output.Free;
  end;
end;

procedure TfrmPediEsto.ExtractFiles(const Filename: String; Diretorio: String);
var
  I, Len: Integer;
  Output, Src: TStream;
  Name: AnsiString;
begin
  Src := TFileStream.Create(Filename, fmOpenRead or fmShareDenyWrite);
  try
    while Src.Size > Src.Position do
    begin
      Src.ReadBuffer(Len, SizeOf(Integer));
      SetLength(Name, Len);
      Src.ReadBuffer(PAnsiString(Name)^, Len);

      Output := TFileStream.Create(Diretorio + Name, fmCreate);
      try
        Src.ReadBuffer(Len, SizeOf(Integer));
        Output.CopyFrom(Src, Len);
      finally
        Output.Free;
      end;
    end;
  finally
    Src.Free;
  end;
end;


GOSTEI 0
POSTAR