Qu'est-ce qu'un flux ? Stream, en termes simples, est un traitement abstrait de données basé sur une approche orientée objet.
outils. Dans le flux, certaines opérations de base de traitement des données sont définies, telles que la lecture des données, l'écriture des données, etc.
Le programmeur effectue toutes les opérations sur le flux sans se soucier de la direction réelle du flux des données à l'autre extrémité du flux. Ne coule pas
Mais il peut traiter des fichiers, de la mémoire dynamique, des données réseau et d'autres formes de données. si tu as raison
Le fonctionnement des flux est très efficace. L'utilisation de la commodité des flux dans les programmes améliorera considérablement l'efficacité de l'écriture des programmes.
Ci-dessous, l'auteur utilise quatre exemples : chiffreur de fichiers EXE, carte de vœux électronique, OICQ maison et écran réseau
Transmission pour illustrer l'utilisation de "stream" dans la programmation Delphi. Certaines des techniques de ces exemples étaient autrefois très douces.
Le secret du fichier n’est pas rendu public, et désormais chacun peut directement citer le code gratuitement.
"Des immeubles de grande hauteur sortent du sol." Avant d'analyser les exemples, comprenons d'abord les concepts de base et les concepts de flux.
Fonctions, ce n'est qu'après avoir compris ces éléments de base que nous pouvons passer à l'étape suivante. Veuillez comprendre attentivement
ces méthodes de base. Bien entendu, si vous les connaissez déjà, vous pouvez sauter cette étape.
1. Concepts de base et déclarations de fonctions des flux dans Delphi
Dans Delphi, la classe de base de tous les objets flux est la classe TStream, qui définit les propriétés communes de tous les flux.
et les méthodes.
Les propriétés définies dans la classe TStream sont présentées comme suit :
1. Taille : Cette propriété renvoie la taille des données dans le flux en octets.
2. Position : cet attribut contrôle la position du pointeur d'accès dans le flux.
Il existe quatre méthodes virtuelles définies dans Tstream :
1. Lire : Cette méthode lit les données du flux. Le prototype de fonction est :
Fonction Read(var Buffer;Count:Longint):Longint;virtuel;abstrait;
Le paramètre Buffer est le buffer placé lors de la lecture des données, Count est le nombre d'octets de données à lire,
La valeur de retour de cette méthode est le nombre réel d'octets lus, qui peut être inférieur ou égal à la valeur spécifiée dans Count.
2. Write : Cette méthode écrit les données dans le flux. Le prototype de fonction est :
Fonction Write(var Buffer;Count:Longint):Longint;virtuel;abstrait;
Le paramètre Buffer est le buffer des données à écrire dans le flux, Count est la longueur des données en octets,
La valeur de retour de cette méthode est le nombre d'octets réellement écrits dans le flux.
3. Recherche : Cette méthode implémente le mouvement du pointeur de lecture dans le flux. Le prototype de fonction est :
Recherche de fonction (Offset:Longint;Origint:Word):Longint;virtuel;abstrait;
Le paramètre Offset est le nombre d'octets de décalage et le paramètre Origin indique la signification réelle de Offset et ses valeurs possibles.
comme suit:
soFromBeginning:Offset est la position du pointeur depuis le début des données après le mouvement. À ce moment, le décalage doit
Supérieur ou égal à zéro.
soFromCurrent:Offset est la position relative du pointeur après le mouvement et du pointeur actuel.
soFromEnd:Offset est la position du pointeur depuis le début des données après le mouvement. À ce moment, le décalage doit
Inférieur ou égal à zéro.
La valeur de retour de cette méthode est la position du pointeur après le mouvement.
4. Setsize : Cette méthode modifie la taille des données. Le prototype de fonction est :
Fonction Setsize(NewSize:Longint);virtuel;
De plus, plusieurs méthodes statiques sont également définies dans la classe TStream :
1. ReadBuffer : La fonction de cette méthode est de lire les données à partir de la position actuelle dans le flux. Le prototype de fonction est :
PRocédure ReadBuffer(var Buffer;Count:Longint);
La définition des paramètres est la même que celle indiquée ci-dessus. Remarque : lorsque le nombre d'octets de données lus est différent du nombre d'octets à lire
Lorsque les nombres sont différents, une exception EReadError sera générée.
2. WriteBuffer : La fonction de cette méthode est d'écrire des données dans le flux à la position actuelle. Le prototype de fonction est :
Procédure WriteBuffer(var Buffer;Count:Longint);
La définition des paramètres est la même que celle de Write ci-dessus. Remarque : lorsque le nombre d'octets de données écrits est différent du nombre d'octets à écrire
Lorsque les nombres sont différents, une exception EWriteError sera générée.
3. CopyFrom : Cette méthode est utilisée pour copier des flux de données à partir d’autres flux. Le prototype de fonction est :
Fonction CopyFrom(Source:TStream;Count:Longint):Longint;
Le paramètre Source est le flux qui fournit les données et Count est le nombre d'octets de données copiés. Lorsque Count est supérieur à 0,
CopyFrom copie Count octets de données à partir de la position actuelle du paramètre Source lorsque Count est égal à 0,
CopyFrom définit la propriété Position du paramètre Source sur 0, puis copie toutes les données de la Source ;
TStream possède d'autres classes dérivées, dont la plus couramment utilisée est la classe TFileStream. Utiliser TFileStream
Pour accéder aux fichiers à l'aide d'une classe, vous devez d'abord créer une instance. La déclaration est la suivante :
constructeur Create(const Filename:string;Mode:Word);
Filename est le nom du fichier (y compris le chemin) et le paramètre Mode est la manière d'ouvrir le fichier, qui inclut la manière d'ouvrir le fichier.
Mode ouvert et mode partagé, leurs valeurs et significations possibles sont les suivantes :
Mode ouvert :
fmCreate : créez un fichier avec le nom de fichier spécifié ou ouvrez le fichier s'il existe déjà.
fmOpenRead : ouvre le fichier spécifié en mode lecture seule
fmOpenWrite : ouvre le fichier spécifié en mode écriture seule
fmOpenReadWrite : ouvre le fichier spécifié en écriture
Mode de partage :
fmShareCompat : le mode de partage est compatible avec les FCB
fmShareExclusive : n'autorisez en aucun cas d'autres programmes à ouvrir le fichier
fmShareDenyWrite : ne pas autoriser d'autres programmes à ouvrir le fichier en écriture
fmShareDenyRead : ne pas autoriser d'autres programmes à ouvrir le fichier en mode lecture
fmShareDenyNone : d'autres programmes peuvent ouvrir le fichier de n'importe quelle manière
TStream possède également une classe dérivée TMemoryStream, qui est très souvent utilisée dans les applications réelles.
Très fréquemment. C'est ce qu'on appelle un flux mémoire, ce qui signifie créer un objet flux en mémoire. Ses méthodes et fonctions de base suivent
Comme ci-dessus.
Eh bien, avec les bases ci-dessus en place, nous pouvons commencer notre parcours de programmation.
-------------------------------------------------- --------------------------
2. Première application pratique : utiliser des flux pour créer des chiffreurs de fichiers EXE, des bundles, des fichiers auto-extractibles et des programmes d'installation.
Parlons d’abord de la façon de créer un chiffreur de fichiers EXE.
Le principe du chiffreur de fichiers EXE : créer deux fichiers, l'un sert à ajouter des ressources à l'autre fichier EXE
À l’intérieur, cela s’appelle un programme complémentaire. Un autre fichier EXE ajouté est appelé fichier d'en-tête. La fonction de ce programme est
Lisez les fichiers ajoutés à lui-même.
La structure des fichiers EXE sous Windows est relativement complexe. Certains programmes ont également des sommes de contrôle lorsque vous constatez qu'ils ont été modifiés.
Plus tard, ils penseront qu’ils sont infectés par le virus et refuseront de l’exécuter. Nous ajoutons donc le fichier à notre programme,
Cela ne modifiera pas la structure du fichier d'origine. Écrivons d'abord une fonction d'ajout. La fonction de cette fonction est d'ajouter.
Un fichier est ajouté à la fin d'un autre fichier sous forme de flux. La fonction est la suivante :
Fonction Cjt_AddtoFile(SourceFile,TargetFile:string):Boolean;
var
Cible, Source : TFileStream ;
MyFileSize:entier;
commencer
essayer
Source:=TFileStream.Create(SourceFile,fmOpenRead ou fmShareExclusive);
Target:=TFileStream.Create(TargetFile,fmOpenWrite ou fmShareExclusive);
essayer
Target.Seek(0,soFromEnd);//Ajouter des ressources à la fin
Target.CopyFrom(Source,0);
MyFileSize:=Source.Size+Sizeof(MyFileSize);//Calculez la taille de la ressource et écrivez-la à la fin du processus auxiliaire
Target.WriteBuffer(MyFileSize,sizeof(MyFileSize));
enfin
Cible.Gratuit ;
Source.Gratuit ;
fin;
sauf
Résultat :=Faux ;
Sortie;
fin;
Résultat :=Vrai ;
fin;
Avec les bases ci-dessus, nous devrions facilement comprendre cette fonction. où le paramètre SourceFile est
Le fichier à ajouter, le paramètre TargetFile est le fichier cible à ajouter. Par exemple, ajoutez un.exe à
Dans b.exe vous pouvez : Cjt_AddtoFile('a.exe',b.exe'); si l'ajout réussit, renvoyer True sinon
Renvoie faux.
Sur la base de la fonction ci-dessus, nous pouvons écrire la fonction de lecture opposée :
Fonction Cjt_LoadFromFile(SourceFile,TargetFile:string):Boolean;
var
Source : TFileStream ;
Cible : TMemoryStream ;
MyFileSize:entier;
commencer
essayer
Cible :=TMemoryStream.Create ;
Source:=TFileStream.Create(SourceFile,fmOpenRead ou fmShareDenyNone);
essayer
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//Lire la taille de la ressource
Source.Seek(-MyFileSize,soFromEnd);//Localiser l'emplacement de la ressource
Target.CopyFrom(Source,MyFileSize-sizeof(MyFileSize));//Supprimer les ressources
Target.SaveToFile(TargetFile);//Enregistrer dans un fichier
enfin
Cible.Gratuit ;
Source.Gratuit ;
fin;
sauf
Résultat :=faux ;
Sortie;
fin;
Résultat :=vrai ;
fin;
Le paramètre SourceFile est le nom du fichier ajouté et le paramètre TargetFile est le nom du fichier supprimé.
Le nom du fichier cible à enregistrer après le fichier. Par exemple, Cjt_LoadFromFile('b.exe','a.txt'); dans b.exe
Retirez le fichier et enregistrez-le au format .txt. Si l’extraction réussit, elle renvoie True sinon elle renvoie False.
Ouvrez Delphi, créez un nouveau projet et placez un contrôle d'édition Edit1 et deux boutons sur la fenêtre :
Bouton1 et Bouton2. La propriété Caption du bouton est définie respectivement sur « OK » et « Annuler ». exister
Écrivez du code dans l'événement Click de Button1 :
var S : chaîne ;
commencer
S:=ChangeFileExt(application.ExeName,'.Cjt');
si Edit1.Text='790617' alors
commencer
Cjt_LoadFromFile(Application.ExeName,S);
{Sortez le fichier et enregistrez-le dans le chemin actuel et nommez-le "fichier original.Cjt"}
Winexec(pchar(S),SW_Show);{Exécuter "fichier original.Cjt"}
Application.Terminate ; {Quitter le programme}
fin
autre
Application.MessageBox('Le mot de passe est incorrect, veuillez le saisir à nouveau !', 'Le mot de passe est incorrect', MB_ICONERROR+MB_OK);
Compilez ce programme et renommez le fichier EXE en head.exe. Créez un nouveau fichier texte head.rc,
Le contenu est : head exefile head.exe, puis copiez-le dans le répertoire BIN de Delphi et exécutez
La commande Dos Brcc32.exe head.rc générera un fichier head.res Ce fichier est ce que nous voulons.
Fichiers de ressources, conservez-les en premier.
Notre fichier d'en-tête a été créé, créons le programme complémentaire.
Créez un nouveau projet et placez les contrôles suivants : un Edit, un Opendialog et deux Button1
Les propriétés de légende sont définies respectivement sur « Sélectionner un fichier » et « Chiffré ».
Ajoutez une phrase dans le programme source : {$R head.res} et copiez le fichier head.res dans le répertoire courant du programme.
De cette façon, le head.exe vient d'être compilé avec le programme.
Écrivez le code dans l'événement Cilck de Button1 :
si OpenDialog1.Execute alors Edit1.Text:=OpenDialog1.FileName ;
Écrivez le code dans l'événement Cilck de Button2 :
var S:Chaîne;
commencer
S:=ExtractFilePath(Edit1.Text);
si ExtractRes('exefile','head',S+'head.exe') alors
si Cjt_AddtoFile(Edit1.Text,S+'head.exe') alors
si SupprimerFichier(Edit1.Text) alors
si RenameFile(S+'head.exe',Edit1.Text) alors
Application.MessageBox('Cryptage du fichier réussi !','Message',MB_ICONINFORMATION+MB_OK)
autre
commencer
si FileExists(S+'head.exe') alors DeleteFile(S+'head.exe');
Application.MessageBox('Échec du cryptage du fichier !','Message',MB_ICONINFORMATION+MB_OK)
fin;
fin;
Parmi eux, ExtractRes est une fonction personnalisée, utilisée pour extraire head.exe du fichier de ressources.
Fonction ExtractRes(ResType, ResName, ResNewName : String):boolean;
var
Res : TResourceStream;
commencer
essayer
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
essayer
Res.SavetoFile(ResNewName);
Résultat :=vrai ;
enfin
Res.Libre ;
fin;
sauf
Résultat :=faux ;
fin;
fin;
Remarque : Notre fonction ci-dessus ajoute simplement un fichier à la fin d'un autre fichier.
Dans les applications réelles, il peut être modifié pour ajouter plusieurs fichiers, à condition que le décalage soit défini en fonction de la taille et du nombre réels.
L'adresse fera l'affaire. Par exemple, un regroupeur de fichiers ajoute deux programmes ou plus à un fichier d'en-tête.
dans. Les principes des programmes auto-extractibles et des installateurs sont les mêmes, mais avec plus de compression.
Par exemple, nous pouvons référencer une unité LAH, compresser le flux puis l'ajouter, afin que le fichier devienne plus petit.
Décompressez-le simplement avant de le lire.
De plus, l'exemple du chiffreur EXE dans l'article présente encore de nombreuses imperfections. Par exemple, le mot de passe est corrigé comme.
"790617", après avoir retiré l'EXE et l'avoir exécuté, vous devez attendre la fin de son exécution puis le supprimer, etc. Les lecteurs peuvent le modifier eux-mêmes.