1. Descripción general
Al escribir programas de bases de datos en Delphi, a menudo están involucradas operaciones de importación y exportación de datos, como: almacenar datos en una base de datos grande como archivos portátiles para facilitar la lectura en el exterior; importar información de datos almacenada en archivos a otra base de datos; La base de datos como archivos de datos, es más fácil intercambiar datos dentro y entre programas, y evita los engorrosos pasos de intercambiar datos a través de la memoria. Por ejemplo, en el programa de informe general escrito por el autor, este control se utiliza como soporte de información de datos. entrega.
2. Ideas básicas
Como control de almacenamiento de datagramas, debería poder almacenar y leer la información básica del conjunto de datos (como: nombre del campo, nombre para mostrar del campo, tipo de datos del campo, número de registros, número de campos, valor actual del campo especificado). en el registro especificado, etc.), y debería poder proporcionar mejores características de embalaje para facilitar su uso.
Con base en esto, el autor utilizó las características orientadas a objetos de Delphi5.0 para diseñar y desarrollar el control de almacenamiento de datagramas.
3. Método de implementación
Escriba la siguiente unidad de código:
unidad IbDbFile;
interfaz
Utiliza Windows, SysUtils, Clases, Formularios, Db, DbTables, Diálogos;
constante
Bandera = 'Estudio de software Datagram-Jixing';
Tipo
TDsException = Clase (Excepción);
TIbStorage = clase(TComponente)
Privado
FRptTitle: cadena; //Descripción del datagrama de almacenamiento
FPageHead: cadena; //Descripción del encabezado de la página
FPageFoot: string; //Descripción de los pies
FFieldNames: TStrings; //Tabla de nombres de campos
FStreamIndex: TStrings; //índice de campo
FStream: TStream; // Flujo que almacena el contenido del campo
FFieldCount: Entero; //Número de campos
FRecordCount: Entero; //Número de registros
FOpenFlag: Boolean; // Si la secuencia se crea como bandera
protegido
procedimiento Reset; //Reset---borrar el contenido de la secuencia
procedimiento SaveHead(ADataSet: TDataSet; Fp: TStream // Información del encabezado del informe de almacenamiento);
procedimiento LoadTableToStream(ADataSet: TDataSet //Almacenamiento de datos de registro);
procedimiento IndexFields(ADataSet: TDataSet //Guarda los nombres de los campos del conjunto de datos en la lista);
procedimiento GetHead(Fp: TFileStream //Guardar información del encabezado del informe);
procedimiento GetIndex(Fp: TFileStream); //Crear índice de flujo de registros;
procedimiento GetFieldNames(Fp: TFileStream //Leer la tabla de nombres de campo de la secuencia);
función GetFieldName(AIndex: Integer): cadena //Obtener el nombre del campo;
función GetFieldDataType (AIndex: entero): TFieldType;
función GetDisplayLabel(AIndex: Integer): cadena //Obtener el nombre para mostrar del campo;
procedimiento SaveFieldToStream(AStream: TStream; AField: TField //Guardar el campo en la secuencia);
función GetFieldValue(ARecordNo, FieldNo: Integer): cadena //Contenido del campo;
público
Constructor Crear(AOwner: TComponent);
Destructor Destruir; anular;
procedimiento Abierto; //Crea una secuencia para prepararse para almacenar datos
procedimiento SaveToFile(ADataSet: TDataSet; AFileName: cadena //Método de almacenamiento);
procedimiento LoadFromFile(AFileName: cadena); //Cargar datos
procedimiento FieldStream(ARecordNo, FieldNo: entero; var AStream: TStream);
propiedad FieldNames[Índice: Entero]: cadena leída GetFieldName //nombre del campo;
propiedad FieldDataTypes[Índice: Entero]: TFieldType leer GetFieldDataType;
propiedad FieldDisplayLabels[Índice: entero]: cadena leída GetDisplayLabel;
Campos de propiedad [RecNo, FieldIndex: Integer]: cadena leída GetFieldValue;
// propiedad FieldStreams[RecNo, FieldIndex: Integer]: TStream lee GetFieldStream;
propiedad RecordCount: entero leído FRecordCount escribir FRecordCount;
propiedad FieldCount: entero leído FFieldCount escribir FFieldCount;
publicado
propiedad RptTitle: cadena lee FRptTitle escribe FRptTitle;
propiedad PageHead: cadena lee FPageHead escribe FPageHead;
propiedad PageFoot: cadena lee FPageFoot escribe FPageFoot;
fin;
función ReadAChar(AStream: TStream): Char;
función ReadAStr(AStream: TStream): cadena;
función ReadBStr(AStream: TStream; Tamaño: Entero): cadena;
función ReadAInteger(AStream: TStream): Entero;
procedimiento WriteAStr(AStream: TStream; AStr: cadena);
procedimiento WriteBStr(AStream: TStream; AStr: cadena);
procedimiento WriteAInteger(AStream: TStream; AInteger: Entero);
Registro de trámites;
implementación
Registro de trámites;
comenzar
RegisterComponents('Acceso a datos', [TIbStorage]);
fin;
función ReadAChar(AStream: TStream): Char;
var
ACar: Carbón;
comenzar
Astream.Read(AChar, 1);
Resultado := AChar;
fin;
función ReadAStr(AStream: TStream): cadena;
var
Cadena: cadena;
C: Carbón;
comenzar
Cadena := '';
C := ReadAChar(AStream);
Mientras que C <> #0 lo hace
comenzar
Cadena := Cadena + C;
C := ReadAChar(AStream);
fin;
Resultado := Cadena;
fin;
función ReadBStr(AStream: TStream; Tamaño: Entero): cadena;
var
Cadena: cadena;
C: Carbón;
I: Entero;
comenzar
Cadena := '';
Para I: = 1 a la talla
comenzar
C := ReadAChar(AStream);
Cadena := Cadena + C;
fin;
Resultado := Cadena;
fin;
función ReadAInteger(AStream: TStream): Entero;
var
Cadena: cadena;
C: Carbón;
comenzar
Resultado := MaxInt;
Cadena := '';
C := ReadAChar(AStream);
Mientras que C <> #0 lo hace
comenzar
Cadena := Cadena + C;
C := ReadAChar(AStream);
fin;
intentar
Resultado := StrToInt(Str);
excepto
application.MessageBox('¡La cadena actual no se puede convertir a un número entero!', 'Error',
Mb_Ok + Mb_IconError);
fin;
fin;
procedimiento WriteAStr(AStream: TStream; AStr: cadena);
comenzar
AStream.Write(Puntero(AStr)^, Longitud(AStr) + 1);
fin;
procedimiento WriteBStr(AStream: TStream; AStr: cadena);
comenzar
AStream.Write(Puntero(AStr)^, Longitud(AStr));
fin;
procedimiento WriteAInteger(AStream: TStream; AInteger: Integer);
var
S: cuerda;
comenzar
S := IntToStr(AInteger);
WriteAstr(AStream, S);
fin;
Constructor TIbStorage.Create(AOwner: TComponent);
comenzar
heredado Crear (AOwner);
FOpenFlag := False; //Marca para determinar si se crea la secuencia
fin;
Destructor TIbStorage.Destroy;
comenzar
si FOpenFlag entonces
comenzar
Fstream.Gratis;
FStreamIndex.Gratis;
FFieldNames.Gratis;
fin;
heredado Destruir;
fin;
procedimiento TIbStorage.Open;
comenzar
FOpenFlag := Verdadero;
FStream := TMemoryStream.Create;
FStreamIndex := TStringList.Create;
FFieldNames := TStringList.Create;
Reiniciar;
fin;
procedimiento TIbStorage.Reset; //restablecer
comenzar
si FOpenFlag entonces
comenzar
FFieldNames.Claro;
FStreamIndex.Claro;
FStream.Tamaño:= 0;
Título FRpt := '';
FPageHead := '';
Pie de página FP := '';
FFieldCount := 0;
FRecordCount := 0;
fin;
fin;
//-------Guardar parte de datos
procedimiento TIbStorage.SaveToFile(ADataSet: TDataSet; AFileName: cadena);
var
Fp: TFileStream;
I: Entero;
Ch: Carbón;
T1, T2: TDateTime;
Cadena: cadena;
comenzar
si no es FOpenFlag entonces
comenzar
showmessage('El objeto no está abierto');
Salida;
fin;
intentar
si FileExists(AFileName) entonces DeleteFile(AFileName);
Fp := TFileStream.Create(AFileName, fmCreate);
Reiniciar;
SaveHead(ADataSet, Fp); //Guarda la información del encabezado---Instrucciones adicionales
IndexFields(ADataSet); //Guarda la información del campo del conjunto de datos en FFieldName
LoadTableToStream(ADataSet); //Guarda la información de datos del conjunto de datos.
WriteAStr(Fp, FFieldNames.Text); // Información del nombre del campo de almacenamiento
Ch := '@';
Fp.Escribir(Cap, 1);
WriteAStr(Fp, FStreamIndex.Text); //Lista de índice de campos de almacenamiento
Ch := '@';
Fp.Escribir(Cap, 1);
Fp.CopyFrom(FStream, 0);
finalmente
Fp.Libre;
fin;
fin;
procedimiento TIbStorage.SaveHead(ADataSet: TDataSet; Fp: TStream);
var
I: Entero;
Ch: Carbón;
comenzar
si no es ADataSet.Active entonces ADataSet.Active := Verdadero;
WriteAStr(Fp, Bandera);
WriteAStr(Fp, FRptTitle);
WriteAStr(Fp, FPageHead);
WriteAStr(Fp, FPageFoot);
FFieldCount := ADataSet.Fields.Count;
FRecordCount := ADataSet.RecordCount;
WriteAStr(Fp, IntToStr(ADataSet.Fields.Count));
WriteAStr(Fp, IntToStr(ADataSet.RecordCount));
Ch := '@';
Fp.Escribir(Cap, 1);
fin;
procedimiento TIbStorage.IndexFields(ADataSet: TDataSet);
var
I: Entero;
Campo A: Campo TF;
comenzar
Para I: = 0 a ADataSet.Fields.Count - 1 hacer
comenzar
AField := ADataSet.Fields[I];
//No usar FFieldNames.Values[AField.FieldName] := AField.DisplayLabel es para considerar la eficiencia;
FFieldNames.Add(AField.FieldName + '=' + AField.DisplayLabel);
FFieldNames.Add(AField.FieldName + 'DataType=' + IntToStr(Ord(AField.DataType)));
fin;
fin;
procedimiento TIbStorage.LoadTableToStream(ADataSet: TDataSet);
var
No: Entero;
I, J, Tamaño: Entero;
Tmp, Id, Str: cadena; //id=cadena(RecNO) + cadena(FieldNo)
Len: Entero;
Ch: Carbón;
BlobStream: TBlobStream;
comenzar
si no es FOpenFlag entonces
comenzar
showmessage('El objeto no está abierto');
Salida;
fin;
intentar
ADataSet.DisableControls;
ADataSet.Primero;
No := 0;
FStreamIndex.Claro;
FStream.Tamaño:= 0;
Si bien no lo hace ADataSet.Eof
comenzar
No := No + 1;
Para J: = 0 a ADataSet.Fields.Count - 1 hacer
comenzar
Identificación := Inttostr(NO) + '_' + IntToStr(J);
//Crea un índice de la posición de la secuencia, el índice apunta a: Tamaño#0Contenido
FStreamIndex.Add(Id + '=' + IntToStr(FStream.Position));
//Almacenar información del campo en la secuencia
SaveFieldToStream(FStream, ADataSet.Fields[J]);
fin;
ADataSet.Siguiente;
fin;
finalmente
ADataSet.EnableControls;
fin;
fin;
//Si el contenido actual de un campo está vacío o BlobSize<=0, solo el tamaño del campo es 0 y no se escribe ningún contenido.
procedimiento TIbStorage.SaveFieldToStream(AStream: TStream; AField: TField);
var
Tamaño: Entero;
Ch: Carbón;
XF: TStream;
Cadena: cadena;
comenzar
si AField.IsBlob entonces
comenzar
//Cómo almacenar el contenido de un campo TBlobField como una secuencia
Xf := TBlobStream.Create(TBlobField(AField), bmread);
intentar
si Xf.Size > 0 entonces
comenzar
Tamaño := Xf.Tamaño;
WriteAInteger(AStream, Tamaño);
AStream.CopyFrom(Xf, Xf.Tamaño);
fin
demás
WriteAInteger(AStream, 0);
finalmente
XF.Gratis;
fin;
fin
demás
comenzar
Str := AField.AsString;
Tamaño: = Longitud (Str);
WriteAInteger(AStream, Tamaño);
si tamaño <> 0 entonces
AStream.Write(Puntero(Str)^, Tamaño);
//WriteAstr(AStream, Str);
fin;
Ch := '@';
AStream.Write(Cap, 1);
fin;
//------------Cargar datos
procedimiento TIbStorage.LoadFromFile(AFileName: cadena);
var
Fp: TFileStream;
Verificar: cadena;
comenzar
Reiniciar;
intentar
si no existe el archivo (AFileName), entonces
comenzar
showmessage('El archivo no existe:' + AFileName);
Salida;
fin;
Fp := TFileStream.Create(AFileName, fmOpenRead);
Verificar := ReadAStr(Fp);
si marca <> bandera entonces
comenzar
Application.MessageBox('Formato de archivo ilegal', 'Error', Mb_Ok + Mb_IconError);
Salida;
fin;
ObtenerCabeza(Fp);
Obtener nombres de campo (Fp);
Obtener índice(Fp);
FStream.CopyFrom(Fp, Fp.Tamaño-Fp.Posición);
finalmente
Fp.Libre;
fin;
fin;
procedimiento TIbStorage.GetHead(Fp: TFileStream);
comenzar
FRptTitle := ReadAStr(Fp);
FPageHead := ReadAstr(Fp);
FPageFoot := ReadAstr(Fp);
FFieldCount := ReadAInteger(Fp);
FRecordCount := ReadAInteger(Fp);
si ReadAChar(Fp) <> '@' entonces showmessage('GetHead File Error');
fin;
procedimiento TIbStorage.GetFieldNames(Fp: TFileStream);
var
Ch: Carbón;
Cadena: cadena;
comenzar
Cadena := '';
Str := LeerAStr(Fp);
FFieldNames.CommaText := Str;
Ch := LeerACar(Fp);
si Ch <> '@' entonces Showmessage('Cuando se obtienen los nombres de campo Error');
fin;
procedimiento TIbStorage.GetIndex(Fp: TFileStream);
var
Ch: Carbón;
Cadena: cadena;
comenzar
Cadena := '';
Str := LeerAStr(Fp);
FStreamIndex.CommaText := Cadena;
Ch := LeerACar(Fp);
si Ch <> '@' entonces Showmessage('Cuando se obtiene un error en el índice de posición del campo');
fin;
//---------Leer la parte del valor del campo
función TIbStorage.GetFieldValue(ARecordNo, FieldNo: Integer): cadena;
var
Identificación, T: cadena;
Pos: Entero;
Len, I: Entero;
Er: booleano;
comenzar
Resultado := '';
Er := Falso;
si ARecordNo > FRecordCount entonces
Er := verdadero; //ARecordNo := FRecordCount;
si ARecordNo < 1 entonces
Er := Verdadero; // ARecordNo := 1;
si FieldNo >= FFieldCount entonces
Er := Verdadero; // Número de campo := FFieldCount - 1;
si CampoNo < 0 entonces
Er := Verdadero; //Nº de campo := 0;
Si Er entonces
comenzar
Showmessage('El número de registro o la etiqueta del campo está fuera de los límites');
Salida;
fin;
si FFieldCount = 0 entonces Salir;
Identificación := Inttostr(ARecordNO) + '_' + IntToStr(FieldNo);
Pos := StrToInt(FStreamIndex.Values[Id]);
FStream.Posición:= Pos;
//Obtener la longitud del contenido del campo
Len := ReadAInteger(FStream);
si Len > 0 entonces
Resultado := ReadBStr(FStream, Len);
si ReadAChar(FStream) <> '@' entonces
Showmessage('Al leer el campo, se encuentra el error de formato de guardado');
fin;
procedimiento TIbStorage.FieldStream(ARecordNo, FieldNo: entero; var AStream: TStream);
var
Identificación, T: cadena;
Pos: Entero;
Len, I: Entero;
Er: booleano;
comenzar
Er := Falso;
si ARecordNo > FRecordCount entonces
Er := verdadero; //ARecordNo := FRecordCount;
si ARecordNo < 1 entonces
Er := Verdadero; // ARecordNo := 1;
si FieldNo >= FFieldCount entonces
Er := Verdadero; // Número de campo := FFieldCount - 1;
si CampoNo < 0 entonces
Er := Verdadero; //Nº de campo := 0;
Si Er entonces
comenzar
TDsException.Create('Subíndice del índice de la función GetFieldValue fuera de límites');
Salida;
fin;
si FFieldCount = 0 entonces Salir;
Identificación := Inttostr(ARecordNO) + IntToStr(FieldNo);
Pos := StrToInt(FStreamIndex.Values[Id]);
FStream.Position := Pos;
Len := ReadAInteger(FStream);
AStream.CopyFrom(FStream, Len);
fin;
función TIbStorage.GetFieldName(AIndex: Integer): cadena //Obtener el nombre del campo;
comenzar
//Los campos almacenados y los tipos de datos representan la mitad cada uno
si ((AIndex < 0) o (AIndex >= FFieldNames.Count div 2)) entonces
Application.MessageBox('Índice de nombre de campo fuera de límites', 'Error de programa',
Mb_Ok + Mb_IconError)
demás
Resultado := FFieldNames.Names[AIndex*2];
fin;
función TIbStorage.GetFieldDataType(AIndex: Integer): TFieldType //Obtener el nombre del campo;
comenzar
//Los campos almacenados y los tipos de datos representan la mitad cada uno
si ((AIndex < 0) o (AIndex >= FFieldNames.Count div 2)) entonces
Application.MessageBox('El índice del tipo de datos del campo está fuera de los límites', 'Error de programa',
Mb_Ok + Mb_IconError)
demás
Resultado := TFieldType(StrToInt(FFieldNames.Values[FFieldNames.Names[AIndex*2+1]]));
fin;
función TIbStorage.GetDisplayLabel(AIndex: Integer): cadena //Obtener el nombre para mostrar del campo;
comenzar
si ((AIndex < 0) o (AIndex >= FFieldNames.Count)) entonces
Application.MessageBox('Índice de nombre de campo fuera de límites', 'Error de programa',
Mb_Ok + Mb_IconError)
demás
Resultado := FFieldNames.Values[GetFieldName(AIndex)];
fin;
fin.
A través de las pruebas, este control tiene un buen soporte para los controles de conjuntos de datos de uso común, como Ttable, Tquery, TaodTable, TadoQuery, TibTable, TibQuery, etc., y tiene buena eficiencia (prueba: 1100 registros de personal, 23 campos almacenados como archivo tardan aproximadamente 2 artículos de segunda clase).
4. Uso básico de los controles.
1. Almacenar datos de un conjunto de datos en un archivo
IbStorage1.Open; //Crear un flujo de almacenamiento
IbStorage1.SaveToFile(AdataSet, Afilename);
2. Leer información de datos del archivo.
IbAlmacenamiento1.Open;
IbStorage1.LoadFromFile(AfileName);
3. Acceso a los datos en el control de almacenamiento de datagramas.
Valor := IbStorage1.Fields[ArecNo, AfieldNo] //Tipo de cadena
Otros se omiten.
5. Conclusión
Al escribir este control de almacenamiento de datagramas, se resuelve mejor el problema del almacenamiento e intercambio de datos en programas de bases de datos y se proporciona un control práctico para el desarrollo de programas de bases de datos.
El control pasó la depuración bajo el entorno de desarrollo Windows98 y Delphi5.