O que é um fluxo? Stream, simplesmente, é um processamento abstrato de dados baseado em orientação a objetos.
ferramentas. No fluxo, são definidas algumas operações básicas para processamento de dados, como leitura de dados, gravação de dados, etc.
O programador executa todas as operações no fluxo sem se preocupar com a direção real do fluxo dos dados na outra extremidade do fluxo. Fluir não
Mas pode processar arquivos, memória dinâmica, dados de rede e outras formas de dados. se você estiver certo
A operação de fluxos é muito proficiente. Usar a conveniência dos fluxos em programas melhorará muito a eficiência da escrita de programas.
Abaixo, o autor utiliza quatro exemplos: criptografador de arquivos EXE, cartão eletrônico, OICQ caseiro e tela de rede
Transmissão para ilustrar o uso de "stream" na programação Delphi. Algumas das técnicas nestes exemplos costumavam ser muito suaves.
O segredo do arquivo não é aberto ao público e agora todos podem citar o código diretamente e gratuitamente.
“Edifícios altos surgem do solo.” Antes de analisar os exemplos, vamos primeiro entender os conceitos básicos e conceitos de fluxo.
Funções, somente depois de compreender essas coisas básicas podemos prosseguir para a próxima etapa. Por favor, entenda com atenção
esses métodos básicos. Claro, se você já estiver familiarizado com eles, poderá pular esta etapa.
1. Conceitos básicos e declarações de funções de streams em Delphi
No Delphi, a classe base de todos os objetos stream é a classe TStream, que define as propriedades comuns de todos os streams.
e métodos.
As propriedades definidas na classe TStream são apresentadas da seguinte forma:
1. Tamanho: Esta propriedade retorna o tamanho dos dados do fluxo em bytes.
2. Posição: Este atributo controla a posição do ponteiro de acesso no fluxo.
Existem quatro métodos virtuais definidos no Tstream:
1. Leitura: Este método lê dados do fluxo. O protótipo da função é:
Função Leitura(var Buffer;Contagem:Inteiro longo):Inteiro longo;virtual;abstrato;
O parâmetro Buffer é o buffer colocado durante a leitura dos dados, Count é o número de bytes de dados a serem lidos,
O valor de retorno deste método é o número real de bytes lidos, que pode ser menor ou igual ao valor especificado em Count.
2. Gravação: Este método grava dados no fluxo. O protótipo da função é:
Função Write(var Buffer;Contagem:Inteiro longo):Inteiro longo;virtual;abstrato;
O parâmetro Buffer é o buffer dos dados a serem gravados no fluxo, Count é o comprimento dos dados em bytes,
O valor de retorno deste método é o número de bytes realmente gravados no fluxo.
3. Busca: Este método implementa o movimento do ponteiro de leitura no fluxo. O protótipo da função é:
Busca de Função (Deslocamento:Inteiro Longo;Origem:Word):Inteiro Longo;virtual;abstrato;
O parâmetro Offset é o número de bytes de offset, e o parâmetro Origin aponta o real significado do Offset e seus possíveis valores.
do seguinte modo:
soFromBeginning:Offset é a posição do ponteiro desde o início dos dados após o movimento. Neste momento, o deslocamento deve
Maior ou igual a zero.
soFromCurrent:Offset é a posição relativa do ponteiro após o movimento e o ponteiro atual.
soFromEnd:Offset é a posição do ponteiro desde o início dos dados após o movimento. Neste momento, o deslocamento deve
Menor ou igual a zero.
O valor de retorno deste método é a posição do ponteiro após o movimento.
4. Setsize: Este método altera o tamanho dos dados. O protótipo da função é:
Função Setsize(NewSize:Longint);virtual;
Além disso, vários métodos estáticos também são definidos na classe TStream:
1. ReadBuffer: A função deste método é ler dados da posição atual no fluxo. O protótipo da função é:
Procedimento ReadBuffer(var Buffer;Contagem:Inteiro longo);
A definição dos parâmetros é a mesma da leitura acima. Nota: Quando o número de bytes de dados lidos for diferente dos bytes que precisam ser lidos
Quando os números forem diferentes, será gerada uma exceção EReadError.
2. WriteBuffer: A função deste método é gravar dados no fluxo na posição atual. O protótipo da função é:
Procedimento WriteBuffer(var Buffer;Contagem:Inteiro longo);
A definição dos parâmetros é a mesma do Write acima. Nota: Quando o número de bytes de dados gravados for diferente dos bytes que precisam ser gravados
Quando os números forem diferentes, será gerada uma exceção EWriteError.
3. CopyFrom: Este método é usado para copiar fluxos de dados de outros fluxos. O protótipo da função é:
Função CopyFrom(Fonte:TStream;Count:Longint):Longint;
O parâmetro Source é o fluxo que fornece os dados e Count é o número de bytes de dados copiados. Quando a contagem é maior que 0,
CopyFrom copia Count bytes de dados da posição atual do parâmetro Source quando Count é igual a 0,
CopyFrom define a propriedade Position do parâmetro Source como 0 e copia todos os dados de Source;
TStream possui outras classes derivadas, das quais a mais comumente usada é a classe TFileStream. Usando TFileStream
Para acessar arquivos usando uma classe, você deve primeiro criar uma instância. A declaração é a seguinte:
construtor Create(const Nome do arquivo:string;Modo:Word);
Nome do arquivo é o nome do arquivo (incluindo o caminho) e o parâmetro Modo é a forma de abrir o arquivo, que inclui como abrir o arquivo.
Modo aberto e modo compartilhado, seus possíveis valores e significados são os seguintes:
Modo aberto:
fmCreate: Crie um arquivo com o nome de arquivo especificado ou abra o arquivo se ele já existir.
fmOpenRead: abre o arquivo especificado no modo somente leitura
fmOpenWrite: abre o arquivo especificado no modo somente gravação
fmOpenReadWrite: abre o arquivo especificado para gravação
Modo de compartilhamento:
fmShareCompat: o modo de compartilhamento é compatível com FCBs
fmShareExclusive: Não permita que outros programas abram o arquivo de forma alguma
fmShareDenyWrite: Não permite que outros programas abram o arquivo para gravação
fmShareDenyRead: Não permite que outros programas abram o arquivo no modo de leitura
fmShareDenyNone: Outros programas podem abrir o arquivo de qualquer forma
TStream também possui uma classe derivada TMemoryStream, que é usada com muita frequência em aplicativos reais.
Muito frequentemente. É chamado de fluxo de memória, o que significa criar um objeto de fluxo na memória. Seus métodos e funções básicas seguem
O mesmo que acima.
Bem, com a base acima estabelecida, podemos iniciar nossa jornada de programação.
-------------------------------------------------- --------------------------
2. Aplicação prática um: usando streams para criar criptografadores de arquivos EXE, pacotes, arquivos autoextraíveis e programas de instalação
Vamos primeiro falar sobre como criar um criptografador de arquivo EXE.
O princípio do criptografador de arquivo EXE: crie dois arquivos, um é usado para adicionar recursos ao outro arquivo EXE
Por dentro, é chamado de programa complementar. Outro arquivo EXE adicionado é chamado de arquivo de cabeçalho. A função deste programa é
Leia os arquivos adicionados a si mesmo.
A estrutura dos arquivos EXE no Windows é relativamente complexa. Alguns programas também possuem somas de verificação quando você descobre que eles foram alterados.
Mais tarde, eles pensarão que estão infectados pelo vírus e se recusarão a executá-lo. Então, adicionamos o arquivo ao nosso programa,
Isso não alterará a estrutura original do arquivo. Vamos primeiro escrever uma função add. A função desta função é adicionar.
Um arquivo é anexado ao final de outro arquivo como um fluxo. A função é a seguinte:
Função Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean;
var
Destino,Fonte:TFileStream;
MeuFileSize:inteiro;
começar
tentar
Fonte:=TFileStream.Create(SourceFile,fmOpenRead ou fmShareExclusive);
Destino:=TFileStream.Create(TargetFile,fmOpenWrite ou fmShareExclusive);
tentar
Target.Seek(0,soFromEnd);//Adiciona recursos ao final
Target.CopyFrom(Fonte,0);
MyFileSize:=Source.Size+Sizeof(MyFileSize);//Calcula o tamanho do recurso e escreve-o no final do processo auxiliar
Target.WriteBuffer(MyFileSize,sizeof(MyFileSize));
finalmente
Alvo.Grátis;
Fonte.Grátis;
fim;
exceto
Resultado:=Falso;
Saída;
fim;
Resultado:=Verdadeiro;
fim;
Com a base acima, devemos compreender facilmente esta função. onde está o parâmetro SourceFile
O arquivo a ser adicionado, o parâmetro TargetFile é o arquivo de destino a ser adicionado. Por exemplo, adicione a.exe a
Em b.exe você pode: Cjt_AddtoFile('a.exe',b.exe'); se a adição for bem-sucedida, retorne True caso contrário.
Retorne falso.
Com base na função acima, podemos escrever a função de leitura oposta:
Função Cjt_LoadFromFile(SourceFile,TargetFile:string):Boolean;
var
Fonte:TFileStream;
Alvo:TMemoryStream;
MeuFileSize:inteiro;
começar
tentar
Destino:=TMemoryStream.Create;
Fonte:=TFileStream.Create(SourceFile,fmOpenRead ou fmShareDenyNone);
tentar
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//Lê o tamanho do recurso
Source.Seek(-MyFileSize,soFromEnd);//Localiza o local do recurso
Target.CopyFrom(Source,MyFileSize-sizeof(MyFileSize));//Remover recursos
Target.SaveToFile(TargetFile);//Salvar no arquivo
finalmente
Alvo.Grátis;
Fonte.Grátis;
fim;
exceto
Resultado:=falso;
Saída;
fim;
Resultado:=verdadeiro;
fim;
O parâmetro SourceFile é o nome do arquivo adicionado e o parâmetro TargetFile é o nome do arquivo retirado.
O nome do arquivo de destino a ser salvo após o arquivo. Por exemplo, Cjt_LoadFromFile('b.exe','a.txt');
Retire o arquivo e salve-o como a.txt. Se a extração for bem-sucedida, retorna True, caso contrário, retorna False.
Abra o Delphi, crie um novo projeto e coloque um controle Edit Edit1 e dois Buttons na janela:
Botão1 e Botão2. A propriedade Caption do botão está definida como "OK" e "Cancelar", respectivamente. existir
Escreva o código no evento Click do Button1:
var S: string;
começar
S:=ChangeFileExt(application.ExeName,'.Cjt');
se Edit1.Text='790617' então
começar
Cjt_LoadFromFile(Application.ExeName,S);
{Retire o arquivo e salve-o no caminho atual e nomeie-o como "arquivo original.Cjt"}
Winexec(pchar(S),SW_Show);{Execute "arquivo original.Cjt"}
Application.Terminate;{Sair do programa}
fim
outro
Application.MessageBox('A senha está incorreta, digite novamente!', 'A senha está incorreta', MB_ICONERROR+MB_OK);
Compile este programa e renomeie o arquivo EXE para head.exe. Crie um novo arquivo de texto head.rc,
O conteúdo é: head exefile head.exe, copie-os para o diretório BIN do Delphi e execute
O comando Dos Brcc32.exe head.rc irá gerar um arquivo head.res Este arquivo é o que queremos.
Arquivos de recursos, guarde-os primeiro.
Nosso arquivo de cabeçalho foi criado, vamos criar o programa add-in.
Crie um novo projeto e coloque os seguintes controles: um Edit, um Opendialog e dois Button1
As propriedades da legenda são definidas como "Selecionar arquivo" e "Criptografado", respectivamente.
Adicione uma frase no programa fonte: {$R head.res} e copie o arquivo head.res para o diretório atual do programa.
Desta forma, o head.exe agora é compilado junto com o programa.
Escreva o código no evento Cilck do Button1:
se OpenDialog1.Execute então Edit1.Text:=OpenDialog1.FileName;
Escreva o código no evento Cilck do Button2:
var S:String;
começar
S:=ExtractFilePath(Edit1.Text);
se ExtractRes('exefile','head',S+'head.exe') então
se Cjt_AddtoFile(Edit1.Text,S+'head.exe') então
se DeleteFile (Edit1.Text) então
se RenameFile(S+'head.exe',Edit1.Text) então
Application.MessageBox('Criptografia de arquivo bem-sucedida!','Mensagem',MB_ICONINFORMATION+MB_OK)
outro
começar
se FileExists(S+'head.exe') then DeleteFile(S+'head.exe');
Application.MessageBox('Falha na criptografia do arquivo!','Mensagem',MB_ICONINFORMATION+MB_OK)
fim;
fim;
Entre eles, ExtractRes é uma função customizada, que é usada para extrair head.exe do arquivo de recurso.
Função ExtractRes(ResType, ResName, ResNewName: String):boolean;
var
Res: TResourceStream;
começar
tentar
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
tentar
Res.SavetoFile(ResNovoNome);
Resultado:=verdadeiro;
finalmente
Res.Livre;
fim;
exceto
Resultado:=falso;
fim;
fim;
Nota: Nossa função acima simplesmente anexa um arquivo ao final de outro arquivo.
Em aplicações reais, pode ser alterado para adicionar vários arquivos, desde que o deslocamento seja definido de acordo com o tamanho e número reais
O endereço servirá. Por exemplo, um empacotador de arquivos adiciona dois ou mais programas a um arquivo de cabeçalho.
em. Os princípios dos programas e instaladores autoextraíveis são os mesmos, mas com mais compactação.
Por exemplo, podemos referenciar uma unidade LAH, compactar o fluxo e depois adicioná-lo, para que o arquivo fique menor.
Basta descompactá-lo antes de lê-lo.
Além disso, o exemplo do criptografador EXE no artigo ainda apresenta muitas imperfeições. Por exemplo, a senha é corrigida como.
"790617", após retirar o EXE e executá-lo, você deve esperar que ele termine de ser executado e então excluí-lo, etc. Os leitores podem modificá-lo por conta própria.