¿Qué es una corriente? Stream, en pocas palabras, es un procesamiento abstracto de datos basado en orientación a objetos.
herramientas. En la secuencia, se definen algunas operaciones básicas para procesar datos, como leer datos, escribir datos, etc.
El programador realiza todas las operaciones en la secuencia sin preocuparse por la dirección real del flujo de datos en el otro extremo de la secuencia. fluir no
Pero puede procesar archivos, memoria dinámica, datos de red y otras formas de datos. si tienes razón
La operación de flujos es muy competente. El uso de la conveniencia de los flujos en los programas mejorará en gran medida la eficiencia de la escritura de programas.
A continuación, el autor utiliza cuatro ejemplos: cifrado de archivos EXE, tarjeta de felicitación electrónica, OICQ casero y pantalla de red.
Transmisión para ilustrar el uso de "stream" en la programación Delphi. Algunas de las técnicas en estos ejemplos solían ser muy suaves.
El secreto del archivo no está abierto al público y ahora todos pueden citar directamente el código de forma gratuita.
"Los edificios altos se elevan desde el suelo". Antes de analizar los ejemplos, primero comprendamos los conceptos básicos y los conceptos de flujo.
Funciones, sólo después de comprender estos aspectos básicos podremos pasar al siguiente paso. Por favor comprenda cuidadosamente
estos métodos básicos. Por supuesto, si ya estás familiarizado con ellos, puedes saltarte este paso.
1. Conceptos básicos y declaraciones de funciones de flujos en Delphi.
En Delphi, la clase base de todos los objetos de flujo es la clase TStream, que define las propiedades comunes de todos los flujos.
y métodos.
Las propiedades definidas en la clase TStream se presentan de la siguiente manera:
1. Tamaño: esta propiedad devuelve el tamaño de los datos en la secuencia en bytes.
2. Posición: este atributo controla la posición del puntero de acceso en el flujo.
Hay cuatro métodos virtuales definidos en Tstream:
1. Leer: este método lee datos de la transmisión. El prototipo de función es:
Función Leer(var Buffer;Count:Longint):Longint;virtual;abstracto;
El parámetro Buffer es el búfer que se coloca al leer datos, Count es el número de bytes de datos que se leerán,
El valor de retorno de este método es el número real de bytes leídos, que puede ser menor o igual que el valor especificado en Recuento.
2. Escribir: este método escribe datos en la secuencia. El prototipo de función es:
Función Escritura(var Buffer;Count:Longint):Longint;virtual;abstracto;
El parámetro Buffer es el búfer de los datos que se escribirán en la secuencia, Count es la longitud de los datos en bytes.
El valor de retorno de este método es el número de bytes realmente escritos en la secuencia.
3. Buscar: este método implementa el movimiento del puntero de lectura en la secuencia. El prototipo de función es:
Búsqueda de función (Desplazamiento: Entero largo; Origen: Palabra): Entero largo; virtual; abstracto;
El parámetro Desplazamiento es el número de bytes de desplazamiento, y el parámetro Origen señala el significado real de Desplazamiento y sus posibles valores.
como sigue:
soFromBeginning: Offset es la posición del puntero desde el principio de los datos después del movimiento. En este momento, la compensación debe
Mayor o igual a cero.
soFromCurrent: Offset es la posición relativa del puntero después del movimiento y el puntero actual.
soFromEnd:Offset es la posición del puntero desde el principio de los datos después del movimiento. En este momento, la compensación debe
Menor o igual a cero.
El valor de retorno de este método es la posición del puntero después del movimiento.
4. Setsize: este método cambia el tamaño de los datos. El prototipo de función es:
Función Setsize(NewSize:Longint);virtual;
Además, también se definen varios métodos estáticos en la clase TStream:
1. ReadBuffer: la función de este método es leer datos desde la posición actual en la secuencia. El prototipo de función es:
Procedimiento ReadBuffer(var Buffer;Count:Longint);
La definición de parámetros es la misma que en la lectura anterior. Nota: Cuando la cantidad de bytes de datos leídos es diferente de los bytes que deben leerse
Cuando los números son diferentes, se generará una excepción EReadError.
2. WriteBuffer: la función de este método es escribir datos en la secuencia en la posición actual. El prototipo de función es:
Procedimiento WriteBuffer(var Buffer;Count:Longint);
La definición de parámetros es la misma que en Escritura anterior. Nota: Cuando el número de bytes de datos escritos es diferente de los bytes que deben escribirse
Cuando los números son diferentes, se generará una excepción EWriteError.
3. CopyFrom: este método se utiliza para copiar flujos de datos de otros flujos. El prototipo de función es:
Función CopyFrom(Fuente:TStream;Count:Longint):Longint;
El parámetro Fuente es el flujo que proporciona datos y Recuento es el número de bytes de datos copiados. Cuando el recuento es mayor que 0,
CopyFrom copia Cuenta bytes de datos desde la posición actual del parámetro Fuente cuando Cuenta es igual a 0,
CopyFrom establece la propiedad Posición del parámetro Fuente en 0 y luego copia todos los datos de la Fuente;
TStream tiene otras clases derivadas, la más utilizada es la clase TFileStream. Usando TFileStream
Para acceder a archivos usando una clase, primero debe crear una instancia. El comunicado es el siguiente:
constructor Crear(const Nombre de archivo:cadena;Modo:Palabra);
Nombre de archivo es el nombre del archivo (incluida la ruta) y el parámetro Modo es la forma de abrir el archivo, que incluye cómo abrir el archivo.
Modo abierto y modo compartido, sus posibles valores y significados son los siguientes:
Modo abierto:
fmCreate: crea un archivo con el nombre de archivo especificado o abre el archivo si ya existe.
fmOpenRead: abre el archivo especificado en modo de solo lectura
fmOpenWrite: abre el archivo especificado en modo de solo escritura
fmOpenReadWrite: abre el archivo especificado para escribir
Modo compartir:
fmShareCompat: el modo Compartir es compatible con FCB
fmShareExclusive: no permita que otros programas abran el archivo de ninguna manera
fmShareDenyWrite: no permita que otros programas abran el archivo para escribir
fmShareDenyRead: No permita que otros programas abran el archivo en modo lectura
fmShareDenyNone: Otros programas pueden abrir el archivo de cualquier forma
TStream también tiene una clase derivada TMemoryStream, que se usa con mucha frecuencia en aplicaciones reales.
Muy frecuentemente. Se llama flujo de memoria, lo que significa crear un objeto de flujo en la memoria. Sus métodos y funciones básicos siguen
Lo mismo que arriba.
Bueno, con la base anterior establecida, podemos comenzar nuestro viaje de programación.
-------------------------------------------------- --------------------------
2. Aplicación práctica uno: uso de secuencias para crear cifradores de archivos EXE, paquetes, archivos autoextraíbles y programas de instalación
Primero hablemos de cómo crear un cifrado de archivos EXE.
El principio del cifrado de archivos EXE: cree dos archivos, uno se usa para agregar recursos al otro archivo EXE
En el interior, se llama programa complementario. Otro archivo EXE que se agrega se llama archivo de encabezado. La función de este programa es
Lea los archivos agregados a sí mismo.
La estructura de los archivos EXE en Windows es relativamente compleja. Algunos programas también tienen sumas de verificación cuando descubre que han sido modificadas.
Más tarde, pensarán que están infectados por el virus y se negarán a ejecutarlo. Entonces agregamos el archivo a nuestro programa,
Esto no cambiará la estructura del archivo original. Primero escribamos una función de suma. La función de esta función es sumar.
Un archivo se agrega al final de otro archivo como una secuencia. La función es la siguiente:
Función Cjt_AddtoFile(SourceFile,TargetFile:string):Booleano;
var
Destino, Fuente: TFileStream;
MiTamañoDeArchivo: entero;
comenzar
intentar
Fuente:=TFileStream.Create(SourceFile,fmOpenRead o fmShareExclusive);
Destino:=TFileStream.Create(TargetFile,fmOpenWrite o fmShareExclusive);
intentar
Target.Seek(0,soFromEnd);//Agregar recursos al final
Destino.CopyFrom(Fuente,0);
MyFileSize:=Source.Size+Sizeof(MyFileSize);//Calcule el tamaño del recurso y escríbalo al final del proceso auxiliar
Target.WriteBuffer(MyFileSize,sizeof(MyFileSize));
finalmente
Objetivo.Gratis;
Fuente.Gratis;
fin;
excepto
Resultado:=Falso;
Salida;
fin;
Resultado:=Verdadero;
fin;
Con la base anterior, deberíamos entender fácilmente esta función. donde está el parámetro SourceFile
El archivo que se agregará, el parámetro TargetFile es el archivo de destino que se agregará. Por ejemplo, agregue un.exe a
En b.exe puedes: Cjt_AddtoFile('a.exe',b.exe'); si la adición se realiza correctamente, devuelve True en caso contrario.
Devuelve falso.
Basado en la función anterior podemos escribir la función de lectura opuesta:
Función Cjt_LoadFromFile(SourceFile,TargetFile:string):Boolean;
var
Fuente: TFileStream;
Objetivo:TMemoryStream;
TamañoMiArchivo:entero;
comenzar
intentar
Objetivo:=TMemoryStream.Create;
Fuente:=TFileStream.Create(SourceFile,fmOpenRead o fmShareDenyNone);
intentar
Source.Seek(-sizeof(MyFileSize),soFromEnd);
Source.ReadBuffer(MyFileSize,sizeof(MyFileSize));//Leer el tamaño del recurso
Source.Seek(-MyFileSize,soFromEnd);//Ubique la ubicación del recurso
Target.CopyFrom(Source,MyFileSize-sizeof(MyFileSize));//Eliminar recursos
Target.SaveToFile(TargetFile);//Guardar en archivo
finalmente
Objetivo.Gratis;
Fuente.Gratis;
fin;
excepto
Resultado:=falso;
Salida;
fin;
Resultado:=verdadero;
fin;
El parámetro SourceFile es el nombre del archivo agregado y el parámetro TargetFile es el nombre del archivo eliminado.
El nombre del archivo de destino que se guardará después del archivo. Por ejemplo, Cjt_LoadFromFile('b.exe','a.txt');
Saque el archivo y guárdelo como.txt. Si la extracción es exitosa, devuelve Verdadero; de lo contrario, devuelve Falso.
Abra Delphi, cree un nuevo proyecto y coloque un control de edición Edit1 y dos botones en la ventana:
Botón1 y Botón2. La propiedad Título del botón está configurada en "Aceptar" y "Cancelar" respectivamente. existir
Escribe código en el evento Click del Botón1:
var S: cadena;
comenzar
S:=ChangeFileExt(application.ExeName,'.Cjt');
si Edit1.Text='790617' entonces
comenzar
Cjt_LoadFromFile(Application.ExeName,S);
{Saque el archivo y guárdelo en la ruta actual y asígnele el nombre "archivo original.Cjt"}
Winexec(pchar(S),SW_Show);{Ejecutar "archivo original.Cjt"}
Aplicación.Terminar;{Salir del programa}
fin
demás
Application.MessageBox('¡La contraseña es incorrecta, vuelva a ingresarla!', 'La contraseña es incorrecta', MB_ICONERROR+MB_OK);
Compile este programa y cambie el nombre del archivo EXE a head.exe. Crea un nuevo archivo de texto head.rc,
El contenido es: head exefile head.exe, luego cópielos al directorio BIN de Delphi y ejecútelos
El comando DOS Brcc32.exe head.rc generará un archivo head.res. Este archivo es lo que queremos.
Archivos de recursos, guárdelos primero.
Nuestro archivo de encabezado ha sido creado, creemos el programa complementario.
Cree un nuevo proyecto y coloque los siguientes controles: un Editar, un Opendialog y dos Button1
Las propiedades de Título están configuradas en "Seleccionar archivo" y "Cifrado" respectivamente.
Agregue una oración en el programa fuente: {$R head.res} y copie el archivo head.res al directorio actual del programa.
De esta manera, el head.exe que acaba de compilarse se compila junto con el programa.
Escribe el código en el evento Cilck del Botón1:
si OpenDialog1.Execute entonces Edit1.Text:=OpenDialog1.FileName;
Escribe el código en el evento Cilck del Botón2:
var S: Cadena;
comenzar
S:=ExtractFilePath(Edit1.Texto);
si ExtractRes('exefile','head',S+'head.exe') entonces
si Cjt_AddtoFile(Edit1.Text,S+'head.exe') entonces
si EliminarArchivo(Editar1.Texto) entonces
si RenameFile(S+'head.exe',Edit1.Text) entonces
Application.MessageBox('¡Cifrado de archivos exitoso!','Mensaje',MB_ICONINFORMATION+MB_OK)
demás
comenzar
si FileExists(S+'head.exe') entonces DeleteFile(S+'head.exe');
Application.MessageBox('¡Error en el cifrado de archivos!','Mensaje',MB_ICONINFORMATION+MB_OK)
fin;
fin;
Entre ellos, ExtractRes es una función personalizada que se utiliza para extraer head.exe del archivo de recursos.
Función ExtractRes(ResType, ResName, ResNewName: Cadena):boolean;
var
Res: TResourceStream;
comenzar
intentar
Res := TResourceStream.Create(Hinstance, Resname, Pchar(ResType));
intentar
Res.SavetoFile(ResNewName);
Resultado:=verdadero;
finalmente
Res.Libre;
fin;
excepto
Resultado:=falso;
fin;
fin;
Nota: Nuestra función anterior simplemente agrega un archivo al final de otro archivo.
En aplicaciones reales, se puede cambiar para agregar varios archivos, siempre que el desplazamiento se defina de acuerdo con el tamaño y el número reales.
La dirección servirá. Por ejemplo, un paquete de archivos agrega dos o más programas a un archivo de encabezado.
en. Los principios de los instaladores y programas autoextraíbles son los mismos, pero con más compresión.
Por ejemplo, podemos hacer referencia a una unidad LAH, comprimir la secuencia y luego agregarla, para que el archivo se vuelva más pequeño.
Simplemente descomprímalo antes de leerlo.
Además, el ejemplo del cifrado EXE en el artículo todavía tiene muchas imperfecciones. Por ejemplo, la contraseña está arreglada.
"790617", después de sacar el EXE y ejecutarlo, debes esperar a que termine de ejecutarse y luego eliminarlo, etc. Los lectores pueden modificarlo ellos mismos.