Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Problemas con ficheros de datos (https://www.clubdelphi.com/foros/showthread.php?t=2201)

Ane 13-07-2003 22:20:10

Problemas con ficheros de datos
 
Hola,
Estoy haciendo un programa donde necesito almacenar datos que contengan una parte de texto y una parte para números enteros. Para ello, he definido un fichero de datos de la siguiente forma:
type
TReg = record
Txt: TextFile;
num: Integer;
end;
var
FileReg: File of TReg;
Reg: TReg;
Para estudiarlo, he creado un formulario de prueba que contiene un Memo y dos botones. La idea es: introducir una cadena en el Memo, guardarla (presionando el botón btnGuardar) y después ver lo que se ha almacenado (presionando el botón btnVer).
El problema es que si se introducen grandes cadenas, sólo muestra en el Memo el final de dichas cadenas, las parte y no las muestra enteras. No sé qué es lo que está mal, y el por qué hace esto.
Los procedimientos que he empleado son:
procedure TForm1.btnGuardarClick(Sender: TObject);
var
i: Integer;
begin
AssignFile(FileReg, 'C:\T.dat');
ReWrite(FileReg);
AssignFile(Reg.Txt, 'C:\R.txt');
ReWrite(Reg.Txt);
Reg.num:= 0;
for i:= 0 to (Memo1.Lines.Count - 1) do
begin
Write(Reg.Txt, Memo1.lines[i]);
end;
Seek(FileReg,0);
Write(FileReg,Reg);
Memo1.Lines.Clear;
CloseFile(Reg.Txt);
CloseFile(FileReg);
end;

procedure TForm1.btnVerClick(Sender: TObject);
var
buffer: string;
begin
AssignFile(FileReg, 'C:\T.dat');
Reset(FileReg);
AssignFile(Reg.Txt, 'C:\R.txt');
ReWrite(Reg.Txt);
Seek(FileReg,0);
Read(FileReg, Reg);
Reset(Reg.Txt);
while not Eof(Reg.Txt) do
begin
Read(Reg.Txt, buffer);
Memo1.lines.Add(buffer);
end;
CloseFile(Reg.Txt);
Erase(Reg.Txt);
CloseFile(FileReg);
Erase(FileReg);
end;
Estoy comenzando en esto de la programación en Delphi y sé que lo normal es emplear estructuras del tipo:
type
TReg = record
Txt: string[20];
num: Integer;
end;
var
FileReg: File of TReg;
Reg: TReg;
pero en mi caso no puedo emplear esto porque las cadenas a almacenar es muy posible que superen los 255 caracteres.
Si alguien puede darme alguna pista sobre lo que estoy haciendo mal, lo agradecería mucho.
Gracias de antemano por atender mi petición.

Jose_Pérez 14-07-2003 11:00:29

Hola Ane:

A ver si esto te funciona:

Prueba a poner el valor True (verdadero) en la propiedad WordWrap del componente TMemo.

Suerte.

Ane 14-07-2003 11:27:35

Gracias por contestar a mi problema, pero la propiedad WordWrap del TMemo ya estaba a True.
¿alguna pista de qué puede estar mal?
Gracias.

nachoasensio 15-07-2003 09:53:44

Hola:

Hace ya mucho tiempo que el tipo string no tiene la limitación de 255 caracteres en Delphi. La mejor solución es que cambies el registro para que sea:

type Reg = record
Txt : string;
num: integer;
end;


Y luego, en lugar de ir asignando línea a línea el Memo, puedes hacer:

Reg.Txt := Memo1.Text;

Éso te preserva todo el texto, incluyendo tabuladores (si está activo WantTabs) y saltos de línea.


Espero haberte ayudado.

Un saludo

Nacho

__cadetill 15-07-2003 10:40:29

Cita:

Posteado originalmente por nachoasensio
Hace ya mucho tiempo que el tipo string no tiene la limitación de 255 caracteres en Delphi. La mejor solución es que cambies el registro para que sea:

type Reg = record
Txt : string;
num: integer;
end;
jejeje, hola nachoasensio. Esto fue lo primero que se me ocurrio para contestar, pero antes de hacerlo hice la prueba y, claro esta, no funciona :(

Para lo que expones (

****** le di a SUMMIT sin querer, sorry, continua en el de abajo

__cadetill 15-07-2003 10:47:07

Cita:

Posteado originalmente por nachoasensio
Hace ya mucho tiempo que el tipo string no tiene la limitación de 255 caracteres en Delphi. La mejor solución es que cambies el registro para que sea:

type Reg = record
Txt : string;
num: integer;
end;
jejeje, hola nachoasensio. Esto fue lo primero que se me ocurrio para contestar, pero antes de hacerlo hice la prueba y, claro esta, no funciona :(

Para lo que expones (que es lo que yo pensaba), necesitas declarar una variable de tipo File of Reg y, al declararla, te saltara un error muuu bonito que dice que tiene que ser de tamaño fijo una declaracion de ese tipo (mas o menos y traduciendo muu a mi manera).
El error es precisamente por lo que comentas, porque una variable string ya no es solo de 255 caracteres.

La unica solocion que yo le vi, era limitar eso poniendo algo como...

Código:

type Reg = record
        Txt : string[255];
        num: integer;
end;

Pero claro, ya no se podria escribir todo el texto que uno quisiera, te limitas a una cierta cantidad de caracteres que no es lo que desea nuestro amigo/a Ane

Una solucion que se me acaba de ocurrir mientras escribia esto, es que la variable Txt del record lo que indicase fuera el PATH de un nombre de un archivo y que para grabar el contenido de un memo utilizara un metodo de la classe TStrings que es el SaveToFile

Memo1.Lines.SaveToFile('c:\lolo.txt');

y claro, Txt valdria el "c:\lolo.txt"

Espero que os sirva

nachoasensio 15-07-2003 11:14:54

Efectivamente, cadetill tiene razón (eso me pasa por no dedicar más tiempo a pensar en el problema y responder demasiado deprisa).

Otra posible solución es declarar el fichero FileReg directamente como TextFile y "esconder" el número en el propio fichero, delimitado por un par de caracteres que no se utilicen en el fichero, por ejemplo |45|.´Creo que es la solución más sencilla. La primera línea contiene el número, las siguientes contienen el texto, hasta que se encuentre el delimitador; éste indicará que estamos ante otro registro; es decir:

|45|
dhjfsd sdjklh sdh fs fsd fsld fl sdfsdh fhsdf
sdfs
df
sdf
sdf
sdfsd fgasd fsdjfgsd fjgs d fs
|34|
dfl´ñskd f sdfj sdklñfañs ñfasdññfasñdfsadf
asd f
asd
fa
sd
fsdf asdjkl fasdjklfasd f
ds
fda
s fasd
|27|
sdjk fksf
sdfsd
f
d
s
f


Meter la información es ahora trivial. Para sacarla basta ir buscando la letra '|' con Pos, con algo como:

Memo1.Lines.LoadFromFile('..........');

Texto := Memo1.Text;
cont := 1;

//1ª aparición de '|'
Pos1 := Pos('|', Texto);

while (Pos1 > 0) do
begin

// 2ª aparición de '|'
Pos2 := Pos('|'+Chr(13)+Chr(10), Texto);

//Extraemos el núm. Numero[i] es un array de enteros
Numero[cont] := StrToInt(Copy(Texto, Pos1+1, Pos2-1));

// Eliminamos el '|nº|'+Salto de línea
Texto := Copy(Texto, Pos2+3, Length(Texto));

// Buscamos el siguiente '|'
Pos1 := Pos('|', Texto);

if Pos1 > 0 then
//Extraemos el texto del registro cont
Contenido[cont] := Copy(Texto, 1, Pos1-3); // El -3 es para
// eliminar el salto de línea tras el texto

// Incrementamos el contador
INC(cont);
end; // del while


Tras el bucle en Numero[i] están los números y en Contenido[i] están los contenidos. Hay que iterar desde 1 hasta cont-1.

Nota: el código lo he escrito al vuelo, a lo mejos se me ha pasado algo.

Espero que, ahora sí :D :D , te sirva.

Un saludo

Nacho

jachguate 15-07-2003 11:16:40

Hola.

El almacenar strings largos de longitud variable es un tema interesante y algo complicado, al igual hay varias formas de abordarlo.

Si tu archivo no va a tener muchos registros y no necesitas hacer movimientos rápidos dentro de él, sino podes limitarte a movimietnos secuenciales, podes utilizar un FileStream.

Así, yo lo que hago es primero almacenar en un entero de 32 bits la longitud del texto que sigue y luego ya se cuanto leer del stream. Por supuesto, esto anula cualquier capacidad Seek que querras darle a tu fichero.

Otra opción (la menos elegante) es almacenar en un archivo externo los datos de texto de cada registro, con lo que podes hacer busquedas secuenciales y movimientos rápidos del tipo Seek(NumeroRegistro).

Por último, podes utilizar dos ficheros, uno que contenga el registro con los datos de longitud fija y otro que contenga los datos de texto. De esta forma, en el primero podrias almacenar la posición inicial y la longitud del texto perteneciente al registro actual en el otro archivo, que sería un mar de letras (o una sopa, quizas... :D )

Esa solución, que puede ser la mas apropiada, sin embargo, es dificil de implementar de una forma eficiente, sobre todo si necesitas dar al usuario la capacidad de editar el texto (con lo que podria ya no caber la información en el espacio asignado originalmente y tendrias que moverla al final del archivo, o llevar un registro de los espacios disponibles donde podria caber. Inclusive podrias dividir el texto en varias partes... pero es complicado.

Te sugiero también que penses en la posibilidad de dejarle el trabajo sucio a una base de datos. Inclusive paradox.

Hasta luego.

;)

nachoasensio 15-07-2003 11:21:25

Hola otra vez.

A ojo, creo que falta el else del if, para que cuando no encuentre más '|' guarde el último texto. Así, el if quedaría:

if Pos1 > 0 then
//Extraemos el texto del registro cont
Contenido[cont] := Copy(Texto, 1, Pos1-3)
// El -3 es para
// eliminar el salto de línea tras el texto
else
Contenido[cont] := Texto;

Un saludo

Nacho

Ane 15-07-2003 15:27:27

Muchas gracias a todos por la ayuda.
Voy a seguir el consejo de Nacho a ver qué tal me va.
Hasta pronto.
- Ane -


La franja horaria es GMT +2. Ahora son las 00:37:15.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi