Make your own free website on Tripod.com

Ficheros INI

Hola a todos, en el captítulo anterior os introducía brevemente a los ficheros; hoy os voy a contar como Delphi gestiona los ficheros ini. Por fichero ini se entiende todo fichero que tiene extensión ini, está en formato Ascii, y tiene una estructura interna dividida en secciones. Un claro ejemplo es el famoso Win.ini, que lo podeis encontrar en el directorio windows. Se puede abrir con el Bloc de Notas de windows, aunque windows, incluye un programa visor para ver los ficheros del sistema, que se llama Sysedit, si ejecutais este programa podreis ver el contenido de los ficheros de sistema, entre ellos los de extensión ini.

Los ficheros ini, normalmente, tienen una estructura. Están divididos en bloques o secciones, y dentro de cada sección hay valores que se usan en la configuración del programa que gestiona ese fichero o esa sección. Digo esa sección porque el fichero Win.ini almacena datos sobre windows, y algunos programas añaden secciones a él. Aqui hay que hacer una aclaración ya que esto solo ocurre en Windows 3.x, y Windows 95 tiene este archivo aunque esta en desuso (por compatibilidad).

Los nombres de las secciones están indicados entre corchetes, e inmediatamente van los variables que haya puesto el programa con sus valores. Este es un ejemplo de una entrada de mi fichero Win.ini:
[Ports]
LPT1:=
LPT2:=
LPT3:=
COM1:=9600,n,8,1,x
COM2:=9600,n,8,1,x
COM3:=9600,n,8,1,x
COM4:=9600,n,8,1,x
FILE:=
Como podeis ver es todo Ascii, así que alguien puede pensar que con lo que sabe de ficheros, se puede sentar delante del ordenador y hacerse unas rutinas para leerlos, a lo cual yo respondo que tu mismo, pero que Delphi ya tiene un sistema para leerlos, y muy bueno.

Delphi tiene una unidad donde tiene todos los procedimientos y funciones definidos. Así que lo único que tienes que hacer para poder empezar a trabajar con estos ficheros es añadir la palabra IniFiles a la cláusula uses de tu unidad. Esta es la lista de funciones y procedimientos para leer y escribir en estos ficheros.

Create(Filename) Para acceder a un fichero
Free Cierra el fichero
ReadSecctionValues(Seccion,TString) Para leer todas la variables
ReadSections(TString) Lee las secciones
ReadSection(Seccion,TString) Lee una Seccion entera
ReadString(Seccion,Variable, Defecto) Lee una varible tipo String
ReadInteger(Seccion,Variable,Defecto) Lee una variable tipo integer
ReadBool(Seccion,Variable,Defecto) Lee una variable tipo boleano
WriteString(Seccion,Variable,Valor) Escribe un valor en una Variable.
WriteInteger(Seccion,Variable,Valor) Escribe un valor tipo Integer
WriteBool(Seccion,Variable,Valor) Escribe un valor boleano

Quizas ante tanto nombre os asusteis, pero en cuanto explique un par de detalles el resto será coser un cantar. Para acceder a un fichero ini, lo primero es indicar que fichero es, y eso se hace cuando creamos el objeto. He dicho objeto, y lo he soltado así de refilón, resulta que como Delphi es un lenguaje orientado al objeto, y el sistema de lectura/escritura de ficheros ini, es una clase pues hay que inicializarlo. Seguro que hay alguno de esta pensando que se ha metido en un lio, pero Delphi no nos abandona en los momentos dificiles, y el sistema es muy fácil. Un procedimiento genérico (cuando digo genérico es que se puede poner dentro de cualquier procedemiento) seria como sigue:
Var
MiFicheroIni : TiniFile;
Begin
MiFicheroIni := TIniFile.Create ('pepe.ini');
MiFicheroIni.Free;

En este mini programa lo que he hecho crear una variable tipo IniFile, la cual inicializo en la primera línea indicando que el fichero con el cual vamos a trabajar se llama Pepe.ini, después podria hacer lo que me plazca, y al final libero la variable que he creado, para que no ocupe memoria. Atención porque sino se indica el nombre del fichero con la ruta completa se asume que este está en el directorio Windows, y NO donde se esta ejecutando tu programa. Si quieres acceder al fichero dentro de otro directorio, debes ponerlo así:
MificheroIni := TiniFile.Create ('c:\mi directorio\pepe.ini');
Os comento que los ejemplo que voy a poner trabajarán en el directorio donde se ejecuta la aplicación. Antes de que se me pase, cuando el fichero no se encuentra este es creado.

Vamos hacer un ejemplo donde se usen las principales funciones. Para lo cual construye un formulario como este, con dos botones, dos campos edit, un CheckBox, y un par de etiquetas.

Como os dije, el fichero se creará en el directorio donde se ejecuta este programa, así que para ello debemos saber donde se ejecuta, la manera que yo he usado es declarar un variable en la seccion privada de la unidad, la cual contendrá el directorio y el nombre del fichero, y estos datos le serán asignados en el momento de la creación del formulario, así que este procedimiento será como sigue:
procedure TForm1.FormCreate(Sender: TObject);
begin
Fichero := ExtractFileDir (ParamStr(0))+'\Fichero.ini';
end;
El truco para saber el directorio donde está ejecutandose el programa, está en ParamStr, el cual contiene en su elemento 0 (es un array), el nombre con la ruta completa del programa. Con la función ExtractFileDir obtengo solo la ruta.

El LeerDatos, que se llama Button1, tiene las siguientes líneas de código:
procedure TForm1.Button1Click(Sender: TObject);
Var
MiFichero : TIniFile;
Edad : Integer;
begin
MiFichero := TiniFile.Create (Fichero);
Edit1.Text := MiFichero.ReadString ('Usuario','Nombre','Desconocido');
Edad := MiFichero.ReadInteger ('Usuario','Edad',99);
CheckBox1.Checked := MiFichero.ReadBool ('Usuario','Español',True);
MiFichero.Free;
Edit2.Text := IntToStr (Edad);
end;

Las funciones de lectura de datos devuelven los valores en el formato que los leen. Así cuando usamos ReadString la variable que recoge los datos debe ser un String, cae de cajón, pero por si las moscas. Además tienen tres parametros, el primero es el nombre de la sección, el segundo el nombre de la variable, y el tercero el valor por defecto, en el caso que no exista tal variable, sección, o incluso si el fichero no existiese y fuera creado en el momento de su apertura. Como la edad he decido almacenarla como un valor numérico (integer), para poderla mostrarla en el campo Edit2 he de convertirla a texto, que es lo que hace la última línea.

El procedimiento de escritura es similar:
procedure TForm1.Button2Click(Sender: TObject);
Var
MiFichero : TIniFile;
Edad : Integer;
begin
Edad := StrToInt (Edit2.Text);
MiFichero := TiniFile.Create (Fichero);
MiFichero.WriteString ('Usuario','Nombre',Edit1.Text);
MiFichero.WriteInteger ('Usuario','Edad',Edad);
MiFichero.WriteBool ('Usuario','Español',CheckBox1.Checked);
MiFichero.Free;
end;
Fijaros que el procedimiento es casi indentico al anterior, pero esta vez se usan las ordenes de escritura. Aqui ocurre lo mismo, si el fichero, la seccion, o la variable no existen son creadas. Como regla general se puede decir que si al leer o escribir algo no existe, este es creado.

He dejado atrás funciones que son: ReadSectionValues, ReaSections y ReadSection, las cuales tienen como parametros variables de tipo TStrings, las cuales más que ser una variable es un objeto, el cual no esta de más que vallas tratando porque es muy potente. Básicamente es una lista de cadenas, algo así como un Array o Matriz, pero se pueden hacer muchas cosas con el, añadir elementos, borrarlos, acceder por el indice, ordenarlos, etc. Y lo mejor es que los componentes que usan esten objeto lo hacen practicamente todo ellos. Un componente que usa este objeto son los TListBox, es el séptimo componente empezando por la derecha en la paleta Standar.
Estas funciones leen partes de un fichero ini. Así ReadSectionValues, lee los valores de las variables contenidas en una seccion. ReadSections, lee el nombre de las secciones de un fichero ini, y ReadSection lee el nombre de las variables de la sección. He hecho un pequeño ejemplo que lee de nuestro fichero ini.

He puesto en un formulario tres botones que invocan a estos tres procedimientos y un TListBox, el cual su propiedad items, es del tipo TStrings. Esta es la imagen del formulario que preparé y los tres procedimientos.


procedure TForm1.Button1Click(Sender: TObject);
Var
MiFichero : TiniFile;
begin
MiFichero := TIniFile.Create (Fichero);
MiFichero.ReadSection ('Usuario',ListBox1.Items);
MiFichero.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
Var
MiFichero : TiniFile;
begin

MiFichero := TIniFile.Create (Fichero);
MiFichero.ReadSections (ListBox1.Items);
MiFichero.Free;

end;

procedure TForm1.Button3Click(Sender: TObject);
Var
MiFichero : TiniFile;
begin
MiFichero := TIniFile.Create (Fichero);
MiFichero.ReadSectionValues ('Usuario',ListBox1.Items);
MiFichero.Free;

end;

Bueno pues los ficheros ini no tienen más secretos, solo comentar que yo personalmente prefiero trabajar sobre un fichero ini propio que tocar en el win.ini. El motivo es que así el fichero ini lo creo en el directorio donde esta el programa ejecutable, con lo que obtengo una ventaja, y es que es que si el usuario borra el programa, borrando el directorio donde está el programa ya borra el fichero ini, y no se queda en el directorio Windows y si hubiera añadido entradas al fichero win.ini este no quedaria engordado inultilmente.

Por último comentaros que si alguien necesita almacenar el tipo de fuente en un fichero de este tipo, no lo puede hacer directamente, sino que hay que programar las rutinas , aunque existe unas rutinas escritas por Jose Alfredo Garcia Guirado(jgarcia@pinos.com), las cuales publico en The Unofficial Newsletter of Delphi Users , en el número18 de Noviembre de 1996. En mi página de enlaces teneis un enlace a esta publicación.
He escrito a este señor para publicar aqui su rutina, pero no he obtenido respuesta, así que lo único que puedo hacer es indicar donde se obtiene esta rutina, y si teneis alguna duda de como usarla, me mandais un correo.