Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 29-07-2007
xaguilars xaguilars is offline
Miembro
 
Registrado: jul 2007
Posts: 22
Poder: 0
xaguilars Va por buen camino
Es posible trabajar con un fichero de estructura variable?

Hola tengo un problemilla aver si me podéis ayudar...
Estoy haciendo una aplicación para gestionar MP3 además de info relacionada con el álbum y los artistas...

Trabajo con registros (record) porque aun no sé utilizar bases de datos. Quisiera saber si hay una manera de hacer lo siguiente:

Código Delphi [-]
type
  TSongInfo = Record
      Title: string [255];
      {etc.}
  end;
  TAlbumInfo = array of TSongInfo;
  TDatafile = File of TAlbumInfo;

Esta estructura como tal, según mi delphi 2006, no está permitida porque debería definir un límite en la matriz para poder utilizar TAlbumInfo en un fichero de registros.

Código Delphi [-]
type
  TSongInfo = Record
      Title: string [255];
      {etc.}
  end;
  TAlbumInfo = array [0..19] of TSongInfo;
  TDatafile = File of TAlbumInfo;
Ahora sí me deja compilar. No da error en la estructura de datos. Un álbum podrá tener máximo 20 canciones. Pero el problema es... ¿qué pasa si tengo álbums de más de 20 canciones?

Alguien me puede dar una solución? Gracias!
Responder Con Cita
  #2  
Antiguo 29-07-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Hola xaguilars,
¿Estás seguro de que puedes hacer un archivo de arrays de registros? Yo hice la prueba... pero me resulta extraño el heho de que el compilador acepte algo como lo que tu dices.
Se puede hacer un file of records, ¿pero... un file de arrays? Como dije... no hice la prueba...

Para darte mayor libertad al asunto de guardar una cantidad arbitraria de canciones, yo creo que podrías considerar el uso de un TStringList. Ya que cuenta con LoadFromFile() y SaveToFile() que lo que hace es abrir y guardar el contenido de un archivo.

Podrías valerte del empleo de una "marca" para determinar cuando termina un album y empieza otro.
Podrías hacer algo como:

*ALBUM:Un nombre#20
$Info cancion 1
$Info cancion 2
...
$cancion20

La idea es que *ALBUM sea como cabecera del album, los dos puntos una marca para indicar que lo que sigue es el nombre del album, y # correspondería a la marca que establece la cantidad de canciones que tiene el album.
Para cada canción del album, siguiendo con el ejemplo: se indica que su "cabecera" es el símbolo $.

Es una alternativa,... no es la mejor... pero a lo mejor te resulta.
Yo hice algo parecido... para hacer un manejo de una playlist (ultima versión). Chequealo por si te interesa.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #3  
Antiguo 29-07-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Si se trata de almacenar información en archivos y no usar bases de datos ahí están los formatos INI y XML. No se reinventa la rueda y por otro lado da juego a que estos archivos puedan leerse no sólo desde nuestra aplicación, por ejemplo, sino por cualquier progama capaz de procesar estos formatos. Vamos, digo yo, ¿eh?
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #4  
Antiguo 29-07-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Hola Dec, también estuve pensando en la posibilidad de un archivo INI... Y puede que sea recomendable. Al menos yo lo imagino algo así:

[ALBUM 1]
Cantidad=20
Cancion 1=titulo canción 1#Artista$Duracion@etc...
Cancion 2=titulo canción 2#Artista$Duracion@etc...
....

Aunque aquel ejemplo de manejo de PlayList que hice hace ya bastante tiempo no es tan diferente a la manera en que trabaja un archivo INI.
Mi idea, tal vez un poco descabellada, es guardar toda la info de cada canción en una línea. Una vez que se invoca a ReadString(), mediante alguna función o procedimiento leer cada "marca" y extraer la información entre ellas.

Habría que ver que dice xaguilars.
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #5  
Antiguo 29-07-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Sí; tal vez un archivo INI no sería lo más adecuado, pero, ¿qué me dices de un archivo XML? Ahí puedes incluso inventarte tu propia "estructura del documento". Tal vez por ahí pudieran ir los tiros, pero, también como tú dices, y, en todo caso, a ver qué dice el compañero que inició este Hilo.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #6  
Antiguo 29-07-2007
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: jul 2004
Ubicación: Salta, Argentina
Posts: 5.582
Poder: 25
Delphius Va camino a la fama
Cita:
Empezado por Dec
¿qué me dices de un archivo XML?
Se que un XML es un archivo al que se puede diseñar su propia estructura, fuera de eso no se nada.
Como no lo empleo y no termino de comprender sus propósitos no opino mucho.
He visto muchos archivos XML pero de comprender su funcionamiento no puedo decir. Tal vez les parezca un poco tonto pero me cuesta entender como y para que usarlos.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #7  
Antiguo 29-07-2007
xaguilars xaguilars is offline
Miembro
 
Registrado: jul 2007
Posts: 22
Poder: 0
xaguilars Va por buen camino
Gracias por vuestras propuestas, no me esperaba q me respondieran tan rápido jeje. La verdad es que me han ayudado mucho a pensar y aquí tengo una posible solución...

Código Delphi [-]
 
Type

TSong = packed record
  {EXTERNAL MP3 INFO}
    ID, {POSITION IN DYNAMIC LIST}
    KID:Integer; {KEY IDENTIFIER, UNIQUE}
    Path, {MP3 FILENAME}
    Lyrics: string[255];  {TXT file PATH}
    Rate:0..5; {NUMBER OF STARS}
    Favourite:Boolean;
  {ID3 Tags, INTERNAL MP3 INFO}
    Title,
    Artist,
    Album: string[255];
    Track: Byte;
    Year: string[4];
    Genre,
    Comments,
    Composer,
    Encoder,
    Copyright,
    Link,
    Language: string[255];
  end;

  TAlbum = packed record
    Name: string[255];
    Rate:0..5; {NUMBER OF STARS}
    Favourite:Boolean;
    Songs: String[255]; {ex.: 'KID:#157#158#159#160#7#2514#12477'}
  end;
 
  TSongFile: File of TSong;
  TAlbumFile: File of TAlbum; //Ahora sí podría guardarlo como registros
 
  //ALBUM LIST
  PAlbumNode= ^TAlbumNode; {pointer to TAlbumNode}
 
  TAlbumNode = record
    Info:TAlbum;
    Next:PAlbumNode;
  end;
 
 //SONG LIST
  PSongNode= ^TSongNode; {pointer to TSongNode}

  TSongNode = record
    Info:TSong;
    Next:PSongNode;
  end;
 
(*TAlbum2 = record  {En este caso usaría punteros a las canciones en vez de un string con los KID, pero no sé qué será más eficiente a la hora de programar y de recursos de memoria}
    Name: string[255];
    Rate:0..5; {NUMBER OF STARS}
    Favourite:Boolean;
    Songs: array of PSongNode;
  end;
 PAlbumNode= ^TAlbumNode; {pointer to TAlbumNode}
 
  TAlbumNode = record
    Info:TAlbum2;
    Next:PAlbumNode;
  end;*)

Aquí os dejo un link con el esquema de los dos casos. Aún no lo he implementado. He ido escribiendo conforme me han surgido ideas... pero cuando lo intente os digo que tal... o si me podéis aconsejar antes mejor
En cuanto a lo de XML no sé cómo funciona ni qué posibilidades tiene... Delphi lo trata como un fichero de texto? O puede interpretar el código?

Bueno gracias por todo!

Última edición por xaguilars fecha: 29-07-2007 a las 19:31:02. Razón: el formato de codigo no se visualizaba bien
Responder Con Cita
  #8  
Antiguo 29-07-2007
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

A partir de Delphi 6 (me parece) se cuenta con el componente "TXmlDocument", así como una serie de clases e interfaces de apoyo. Con estas herramientas es posible procesar archivos XML, insertar datos, obtenerlos, actualizarlos, etc.

Además de el componente mencionado, a poco que busques en sitios como Torry's, encontrarás componentes para trabajar con XML desde Delphi. Pero, vamos, que es una opción más, que a lo mejor te basta y sobra como lo estás haciendo.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #9  
Antiguo 30-07-2007
Avatar de cHackAll
[cHackAll] cHackAll is offline
Baneado?
 
Registrado: oct 2006
Posts: 2.159
Poder: 20
cHackAll Va por buen camino
Vaya, si que le dieron muchas soluciónes mientras yo estaba en "otras"; acá les doy la mía que tiene mi estilo clásico:

En realidad no entiendo muy bien cuál es el problema? Incrementar (duplicar o triplicar) el tamaño del vector TAlbumInfo, no es ningun problema tomando en cuenta que el espacio de cada estructura es menor a un Kb. Ahora si el problema es el espacio que utiliza en disco tampoco lo veo muy problemático; si usaras una BD el espacio ocupado por ésta sobrepasaría los 100 Kb. SIN datos.

Sin embargo para ahorrar algo de tamaño te aconsejaría utilizar un archivo sin "tipo", por ejemplo; abres tu pseudo BD, lees el primer caracter (Byte), el cual representará la cantidad de Albunes que tienes; luego entras a un bucle en el que lees un byte y en éste obtienes el tamaño del primer Track; lees el siguiente (segundo) y así susesivamente, claro que es mi perspectiva, y la adecúo un poco para fines genéricos:

Código Delphi [-]
uses Windows;
type
 PTrack = ^TTrack;                                             // TTrack de tipo Puntero
 TTrack = packed record                                        // Tu estructura, parecida al ID3v1 de los MP3s
  Number: Byte;
  Title: string [30];
  Artist: string [30];
  Album: string [30];
  Year: Word;
  Comment: string [30];
  Genre: Byte;
 end;
 
var
 Dummy: Cardinal;                                              // Por optimización Dummy es global
 Items: packed record                                          // Items es el formato en sí de tu "BD"
  Count: Cardinal;                                             // Utilizo una variable de 32 bits; por optimización y el posible uso del ejemplo en otros casos.
  Item: array [0..255] of PTrack;                              // Si te molesta que haya un vecor muy "grande" o inutil; pues lo que se hace es un vector de
 end;                                                          // punteros los cuales son asignados individualmente cada vez que se agrega un registro nuevo.
 
function NewItem: PTrack;                                      // Para asignar/crear un nuevo registro al final del vector
begin
 New(Result);                                                  // Asignamos en memoria un nuevo registro,
 Items.Item[Items.Count] := Result;                            // Lo guardamos en el vector...
 Inc(Items.Count);                                             // e incrementamos el valor que indica la cantidad de elementos del vector.
end;
 
function DelItem(Index: Cardinal): LongBool;                   // Para borrar un registro del vector
begin
 Result := Index < Items.Count;                                // Verificamos si el índice introducido está fuera de rango
 if not Result then Exit;
 Dispose(Items.Item[Index]);                                   // Liberamos la memoria anteriormente asignada...
 while Index < Items.Count do
  begin
   Items.Item[Index] := Items.Item[Index + 1];                 // Vamos recorriendo los elementos del vector para tapar el "hueco" generado...
   Inc(Index);
  end;
 Dec(Items.Count);                                             // y decrementamos nuestro contador
end;
 
function Save(lpFileName: PChar): LongBool;
var hFile, Index: Cardinal;
begin
 hFile := CreateFile(lpFileName, GENERIC_WRITE, 0, nil, CREATE_ALWAYS, 0, 0); // Creamos / pisamos la "BD"
 Result := hFile <> INVALID_HANDLE_VALUE;
 if not Result then Exit;
 Index := 0;
 WriteFile(hFile, Items.Count, 4, Dummy, nil);                 // Guardamos en nuestro archivo el tamaño del vector
 while Index < Items.Count do
  begin
   WriteFile(hFile, Items.Item[Index]^, SizeOf(Items.Item[0]^), Dummy, nil); // Guardamos los elementos del vector
   Inc(Index);
  end;
 CloseHandle(hFile);
end;
 
function Open(lpFileName: PChar): LongBool;
var hFile, Index: Cardinal;
begin
 hFile := CreateFile(lpFileName, GENERIC_READ, 0, nil, OPEN_EXISTING, 0, 0); // Abrimos la "BD"
 Result := hFile <> INVALID_HANDLE_VALUE;
 if not Result then Exit;
 ReadFile(hFile, Index, 4, Dummy, nil);
 while Items.Count < Index do
  ReadFile(hFile, NewItem^, SizeOf(Items.Item[0]^), Dummy, nil);
 CloseHandle(hFile);
end;
 
begin
 Open('pseudoBD.dat');
 if Items.Count >= 4 then
  DelItem(0);
 with NewItem^ do                                              // La forma de acceso tambien se hace sencilla:
  begin
   Number := 1;
   Title := 'Allegro Club Delphi';
   Artist := 'cHackAll';
   Year := 2007;
  end;
 with NewItem^ do                                              // Añadimos otro...
  begin
   Number := 2;
   Title := 'Sinfonía Nº1 Delphiana';
   Artist := 'Moderadores';
   Year := 2008;
  end;
 Save('pseudoBD.dat');
end.

PD: Utilizando una BD; no tendrás que preocuparte por los registros...; integridad, duplicidad, etc, etc, etc... (tampoco de componentes)
Archivos Adjuntos
Tipo de Archivo: zip unaTabla.zip (1,4 KB, 8 visitas)
Responder Con Cita
  #10  
Antiguo 30-07-2007
xaguilars xaguilars is offline
Miembro
 
Registrado: jul 2007
Posts: 22
Poder: 0
xaguilars Va por buen camino
Lightbulb

Hola cHackAll, gracias por tu propuesta. No sé si he entendido mal pero propones utilizar un fichero con un header o cabezera... me parece interesante e igual después estudio como adaptarlo a mi caso. Ayer estuve mejorando mi estructura de datos y me ha quedado de la siguiente manera (en realidad el programa ya estaba funcionando, pero estoy reescribiendo el código porque he añadido la función de manejar álbums que antes no tenía. Era el proyecto final de 1º de FP de Admin de sistemas jeje, ahora tengo k empezar 2º y allí empezamos con las BDD). Bueno ahí va:


Código Delphi [-]
unit UEstructuras;

interface
uses classes, sysutils;

type
  {----------SONGS----------}
  TSong = packed record
  {EXTERNAL MP3 INFO}
    UID:Integer; {UNIQUE IDENTIFIER}
    Path, {MP3 FILENAME}
    Lyrics: string[255];  {TXT file PATH}
    Rate:byte; {NUMBER OF STARS}
    Favourite:Boolean;
    {ID3 Tags, INTERNAL MP3 INFO}
    Title,
    Artist,
    Album: string[255];
    Track: Byte;
    Year: string[4];
    Genre,
    Comments,
    Composer,
    Encoder,
    Copyright,
    Link,
    Language: string[255];
  end;

  TSongFile= File of TSong;

  PSongNode= ^TSongNode; {pointer to TSongNode}

  TSongNode = record
    Prev:PSongNode;
    ID:Integer;
    Info:TSong;
    Next:PSongNode;
  end;

  {----------ALBUMS----------}
  TAlbum = packed record
    UID:Integer; {UNIQUE IDENTIFIER}
    Name: string[255];
    Rate:byte; {NUMBER OF STARS}
    Image: string[255]; {Path of Image}
    Favourite:Boolean;
    Songs: String[255]; {ex.: 'UID:#157#158#159#160#7#2514#12477'}
  end;

  TAlbumFile= File of TAlbum;

  PAlbumNode= ^TAlbumNode; {pointer to TAlbumNode}

  TAlbumNode = record
    Prev:PAlbumNode;
    ID:Integer;
    Info:TAlbum;
    Next:PAlbumNode;
  end;

  {----------ARTISTS----------}
  TArtist = packed record
    UID:Integer; {UNIQUE IDENTIFIER}
    Name, {KEY IDENTIFIER, UNIQUE}
    Country,
    Language,
    Genre,
    Web,
    Comment,
    Albums: string [255]; {ex.: 'UID:#157#158#159#160#7#2514#12477'}
    Photos : array [0..13] of string [255];   {Path of each photo}
  end;

  TArtistFile= File of TArtist;

  PArtistNode= ^TArtistNode; {pointer to TArtistNode}

  TArtistNode = record
    Prev:PArtistNode;
    ID:Integer;
    Info:TArtist;
    Next:PArtistNode;
  end;

  TSearchMethod = (ID, UID, Path, Name);
 
{***********CLASSES***********}
  TSongs = class
     private
      Datapath:string;                              // Ruta al archivo de registros
      function UIDAssign: integer;                  // Asigna el primer número disponible que no se use a los campos UID
    public
      List:PSongNode;                                // Puntero a la lista de canciones
      Counter:Integer;                              // Contador de elementos de la lista
      constructor Create (Filename:string);          // Crea el objeto y llama a LoadDatabase
      procedure LoadDatabase;                        // Carga los registros en la lista de memoria
      procedure SaveDatabase;                        // Guarda la lista en el fichero de registros. Sobreescribe todo.
      function Add (Info: TSong):boolean;            // Añade un nodo, una canción
      function Delete (ID: Integer):boolean;        // Elimina una canción
      function IDReset : boolean;                    // Cuando por ejemplo se elimina un nodo, se reasignan los ID
      procedure DelBrokenLinks;                      // Si una canción no se encuentra en el PC, se da la opción de eliminar el registro
      function Search (Info:TSong; Option:TSearchMethod): PSongNode;  // Busca una canción en la lista dado un criterio de búsqueda
      procedure DropList;                            // Vacía la lista
      procedure FillStringList (Target: TStrings);  // Llena un TStrings con los elementos de la lista
      destructor Destroy; overload;                  // Guarda la lista en el fichero, destruye el objeto y la lista
  end;

  TAlbums = class
    private
      Datapath:string;
      function UIDAssign: integer;
    public
      List:PAlbumNode;
      Counter:integer;
      constructor Create (Filename:string);
      procedure LoadDatabase;
      procedure SaveDatabase;
      function Add (Info: TAlbum):boolean;
      function Delete (ID: Integer):boolean;
      function IDReset : boolean;
      function Search (Info:TAlbum; Option:TSearchMethod): PAlbumNode;
      procedure DropList;
      procedure FillStringList (Target: TStrings);
      destructor Destroy; overload;
  end;

  TArtists = class
    private
      Datapath:string;
      function UIDAssign: integer;
    public
      List:PArtistNode;
      Counter:integer;
      constructor Create (Filename:string);
      procedure LoadDatabase;
      procedure SaveDatabase;
      function Add (Info: TArtist):boolean;
      function Delete (ID: Integer):boolean;
      function DeleteByName (Name:String):boolean;
      function IDReset : boolean;
      function Search (Info:TArtist; Option:TSearchMethod): PArtistNode;
      procedure DropList;
      procedure FillStringList (Target: TStrings);
      destructor Destroy; overload;
  end;

Si os habéis fijado tengo algunos tipos y clases que sólo difieren del tipo de una variable o del tipo que recibe o devuelve un método. He probado de hacer una clase global y después subclases... pero sería lo mismo porque tendría que redefinir... ya que cada método de cada clase utiliza implementaciones distintas, aunque sea sólo cambiar un tipo. No sé hasta qué punto lo puedo simplificar todo.

Me gustaría aprender BDD en delphi, porque si yo supiera haría esto como BDD... pero no sé por donde empezar hay tantas cosas... qué me aconsejáis?

Ah se me olvidaba... si quiero salir de un bucle basta poner 'break;'?

Gracias gente.

Última edición por xaguilars fecha: 30-07-2007 a las 19:09:48.
Responder Con Cita
  #11  
Antiguo 31-07-2007
Avatar de cHackAll
[cHackAll] cHackAll is offline
Baneado?
 
Registrado: oct 2006
Posts: 2.159
Poder: 20
cHackAll Va por buen camino
Bueno, las BDs son como várias hojas de Excel, en cada una de ellas guardas datos como matriz. La gran diferencia entre ésto y una BD como tal (aparte de la obvias) es que cada columna puede tener un formato diferente... a a qué me refiero con ésto: a que puedes guardar en la primera un numero que incremente solo, en la segunda un entero de 32 bits, en la tercera una cadena y en la cuarta una fecha... (ejemplo ehh?)

Lastimosamente en breve me debo ir así que te lo mostraré con un ejemplo mañana.

PD: revisa el Minitutorial de Caral; pues esta "Gueno"...

Saludos.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
variable dentro de una variable molinero1 Varios 3 23-04-2007 12:44:48
Obtener un fichero adjunto a un nodo de un fichero XML muntasil Internet 0 18-07-2006 12:57:57
Es posible trabajar con xp en oracle 10g... uper Oracle 6 07-04-2006 15:44:04
Es posible para solo la estructura de la base de datos de ib expert a Access Nelly Varios 3 10-02-2006 08:37:59
Tipo de Estructura variable pplacido Varios 4 04-01-2004 01:50:16


La franja horaria es GMT +2. Ahora son las 09:50:15.


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