Ir al contenido


Foto

funciones y ficheros .ini


  • Por favor identifícate para responder
17 respuestas en este tema

#1 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 09:18

hola foro.
amigos tengo la siguiente función, la cual tiene el objetivo de leerme un .ini y devolverme las claves (key de una sección especifica)


cpp
  1. // ---obtener los sources y destiny de una tarea
  2. TStrings* getSourceDestinyFromTask(String taskName, bool source) {
  3.  
  4.   String type, ext;
  5.   if (source) {
  6.       type = "source";
  7.       ext = "src";
  8.   }
  9.   else {
  10.       type = "destiny";
  11.       ext = "dst";
  12.   }
  13.  
  14.   // creando nombre de source
  15.   String dir = dirExec + taskName + "." + ext;
  16.   // abriendo ini
  17.   TIniFile *ini = new TIniFile(dir);
  18.   // get keys de las tareas
  19.   TStrins* taskKeys;
  20.   ini->ReadSection(type, taskKeys);//error
  21.   // recorrer keys y almacenar values en salida
  22.         TStrings *sd;   
  23.   // si hay keys
  24.   if (taskKeys->Count > 0) {
  25.       for (int i = 0; i <taskKeys>Count; i++) {
  26.         // get key name
  27.         String key = taskKeys->Strings[i];
  28.         sd->Add(ini->ReadString(type, key, ""));
  29.       }
  30.   }
  31.   delete ini;
  32.   return sd;
  33. }



El error me lo da cuando hago un :
ini->ReadSection(type, taskKeys);
no entiendo el porque, ya que el segundo parámetro de ReadSection es TStrings*.
espero me puedan ayudar gracias
  • 0

#2 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 09:38

Tienes dos errores importantes:  :)

1.- Tratas de crear objetos de la clase TStrings que es abstracta por lo que no lo puedes hacer, en su lugar usa la clase TStringList (derivada de la anterior).

2.- Declaras punteros objetos de la clase TStrings pero no creas el objeto. Debes hacer esto:


cpp
  1. TStringList *taskKeys = new TStringList;


Deberás encargarte de destruir el objeto cuando no te haga falta...


Saludos.
  • 0

#3 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 09:48

scafandra el problema lo tengo cuando hago esto


cpp
  1. TStrings* getSourceDestinyFromTask(String taskName, bool source) {
  2.  
  3. String type, ext;
  4. if (source) {
  5. type = "source";
  6. ext = "src";
  7. }
  8. else {
  9. type = "destiny";
  10. ext = "dst";
  11. }
  12.  
  13. // creando nombre de source
  14. String dir = dirExec + taskName + "." + ext;
  15. // abriendo ini
  16. TIniFile *ini = new TIniFile(dir);
  17. // get keys de las tareas
  18. TStringList *taskKeys = new TStringList;
  19. ini->ReadSection(type, taskKeys);
  20. // recorrer keys y almacenar values en salida
  21. TStringList *sd = new TStringList;
  22. // si hay keys
  23. if (taskKeys->Count > 0) {
  24. for (int i = 0; i < taskKeys->Count; i++) {
  25. // get key name
  26. String key = taskKeys->Strings[i];
  27. sd->Add(ini->ReadString(type, key, ""));
  28. }
  29. }
  30.         delete taskKeys;
  31. delete ini;
  32. return sd;
  33. }


Como puedes ver creo y elimino el taskKeys de tipo StringList, pero no puedo eliminar el sd de tipo TStringList porque es lo que retorno en la funcion. Hay esta el dilema. Me sugieres alguna idea...?
  • 0

#4 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 09:58

Si quieres devolver un puntero puedes hacerlo tranquilamente. Toma la precaución de devolver un nulo si tienes un error en tu función, porque de esta manera el puntero lo destruirás si no es nulo:



cpp
  1. TStrings *Lista = getSourceDestinyFromTask(.....);
  2. ............
  3. if(Lista) delete Lista;



Por su puesto ese puntero no lo destruirá jamas getSourceDestinyFromTask pero tendrás que tenes la precaución de que su resultado siempre sea asignado a un puntero de cuya destrucción estarás encargado tu mismo en la función llamadora.

Saludos.
  • 0

#5 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 10:06

scafandra, no te entendí bien, quieres decir que el puntero a TStringList *sd que creo dentro de la función nunca lo podre eliminar? Si mal no recuerdo una vez trate de hacer algo como eso y poniendo la función en un for bastante largo me llenaba la paginación de la pc bastante rápido. Cual crees que seria el mejor método, recuerda, por favor que después la función se utilizaría así.


cpp
  1. //---obtener destinos
  2. TStrings* taskDestiny = getSourceDestinyFromTask(scc,false);
  3. //obtener origenes
  4. TStrings* taskSource = getSourceDestinyFromTask(scc,true);
  5. ThCopyFiles* ThCopy;
  6. ThCopy = new ThCopyFiles(taskSource, taskDestiny);


  • 0

#6 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 10:22

No me has entendido. Me refiero que lo lo puede destruir la función getSourceDestinyFromTask, puesto que es el valor devuelto. Quien tiene que hacerlo es la función en la que se llama a getSourceDestinyFromTask, como te puse en:



cpp
  1. TStrings *Lista = getSourceDestinyFromTask(.....);
  2. ............
  3. if(Lista) delete Lista;



Vamos a ver si me explico:



cpp
  1. TStrings* getSourceDestinyFromTask()
  2. {
  3.  
  4.   TStrings *sd = new TStringList;
  5.   .......
  6.   if(UnError) return 0; // Si error devuelvo 0.
  7.   .......
  8.   return sd;  // No lo destruyo.
  9. }
  10.  
  11. .......
  12.  
  13. Otrafuncion()
  14. {
  15.   TStrings *Lista = getSourceDestinyFromTask();
  16.   // Si Lista no es cero, la función ha tenido éxtio y podré destruirla pues es un puntero válido.
  17. .........
  18.  
  19.   // Ya no me hace falta Lista, lo destruyo:
  20.   if(Lista) delete Lista;  // Si Lista es válido, la destruyo, en caso contrario si lo hago tendré un error....
  21. }



;)


Saludos.
  • 0

#7 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 10:30

:oNo sabia que se podía hacer eso, muchas gracias escafandra, ya lo probare , espero que todo ande bien. mil gracias. ;)
  • 0

#8 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 10:46

scafandra tengo unas dudas aun.

tengo el siguiente codigo:

cpp
  1. //---obtener destinos
  2. TStrings* taskDestiny = getSourceDestinyFromTask("prueba",false);
  3. //obtener origenes
  4. TStrings* taskSource = getSourceDestinyFromTask("prueba",true);
  5. ThCopyFiles* ThCopy;
  6. ThCopy = new ThCopyFiles(taskSource, taskDestiny);
  7.  
  8. if (taskDestiny) delete taskDestiny;
  9. if (taskSource) delete taskSource;



Sucede que este código tal como esta no me hace una copia porque se eliminan los TStrings* antes de poder hacer las copias, si pongo en comentario las dos ultimas lineas si se hacen las copias, pero no se destruyen los punteros a TStringList *sd que hay dentro de la función : getSourceDestinyFromTask.
Creo que lo que debo hacer es eliminar los TStrings* luego de que se termine la copia, pero eso es lo que no se hacer, me imagino que se debe de hacer en los Thread pero como te comento me quede corto en ese punto también. Podrías ayudarme por favor.
Después de esto creo que nace otra duda sobre dos backups que se estén ejecutando
al mismo tiempo...
muchas gracias

  • 0

#9 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 10:59

Para este caso que planteas puedes optar por destruir esos punteros en el Thread, para ello, un buen momento puede ser al final de la función ThCopyFiles::Execute()

No es muy buena práctica esta forma de actuar porque puede confundirte en un futuro al leer el código. Por otro lado si falla el Thread y se aborta, no se liberarían los punteros.

Mas ortodoxo sería que esos punteros fueran miembros de la clase y tratarlos de destruir en el destructor de la clase o de tu form y cada vez que los tengas que renovar, así como en el evento OnTerminate que definas, Así siempre estarás seguro que si no son nulos, los destruirás antes o después.

Esta forma de actuar es mas clara y segura. Una costumbre que debe ser casi regla obligada es testar que esos punteros no son nulos antes de usarlos o destruirlos, y también es muy sano darles el valor nulo nada mas declararlos. Siempre que destruyas un puntero asígnale un nulo, así no trataras de destruirlo por segunda vez.


cpp
  1.   if(sd){
  2.       delete sd;
  3.       ds = 0;
  4.   }




Saludos.
  • 0

#10 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 11:41

Me parece que lo que planteas esta bien, pero no se como implementar loque me dices

Mas ortodoxo sería que esos punteros fueran miembros de la clase y tratarlos de destruir en el destructor de la clase o de tu form y cada vez que los tengas que renovar, así como en el evento OnTerminate que definas, Así siempre estarás seguro que si no son nulos, los destruirás antes o después.

No se como hacer los punteros miembros d la clase, ni como tratar con ellos dentro del Thread, me podrías ayudar por favor?
  • 0

#11 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 12:19

Vamos a la forma mas ortodoxa y segura.

Supongo que tu estás llamando a getSourceDestinyFromTask desde una función en un form. Supongamos que se llama Form1. Abre el archivo cabecera de Form1 y mira la definición de la clase. en la parte privada añade la declaración de los punteros:



cpp
  1. .....
  2. private:
  3.   TStrings* taskDestiny;
  4.   TStrings* taskSource;
  5. .....



Declara un destructor en la parte pública de la clase:



cpp
  1. public:
  2.   __fastcall TForm1(TComponent* Owner);
  3.   __fastcall ~TForm1();


En el constructor inicializalos a cero.
En el destructor añade esto:



cpp
  1. __fastcall TForm1::~TForm1()
  2. {
  3.     if(taskDestiny) delete taskDestiny;
  4.     if(taskSource)  delete taskSource;
  5. }


Listo.

Pero ya que estamos, quizás debas darle una vuelta de tuerca mas y hacer esto:


cpp
  1. // constructor
  2. __fastcall TForm1::TForm1()
  3. {
  4.     taskDestiny = new TStringList;
  5.     taskSource = new TStringList;
  6. }



y en la función getSourceDestinyFromTask realizar el siguiente cambio: No devuelve nada y le pasas como parámetro el TStrins:



cpp
  1. void getSourceDestinyFromTask(TStrings *sd, String taskName, bool source) ;



Esta opción es la que yo implementaría. :wink:

Saludos.
  • 0

#12 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 01:00

scafandra, un millón de gracias por dedicarme el tiempo. ya probé lo que me haz dado y sin dudas resulta, se copian los ficheros. La duda que me queda es la siguiente:
Toda esta ayuda que me estas brindando la utilizare en el programa de backups que hace tiempo estoy realizando. El programa estará corriendo tiempo indefinido en un servidor por lo que me asusta el tema de si los punteros se destruyen cuando se destruya el formulario, entonces por cada nuevo backup se crean nuevos punteros sueltos que no se destruyen hasta cerra el programa?
Y la otra duda sigue siendo esta:
Se ejecuta una tarea (backup) pasando datos de C:\ a D:\ 30 Gigas duración 3horas
Se ejecuta otra tarea (mientras la primera sigue ejecutándose) pasando datos de C:\prueba a D:\prueba 10 Gigas duración 10 min.
La gran cuestión es: se afecta la primera tarea?
Muchas gracias scafandra
  • 0

#13 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 01:30

El programa estará corriendo tiempo indefinido en un servidor por lo que me asusta el tema de si los punteros se destruyen cuando se destruya el formulario, entonces por cada nuevo backup se crean nuevos punteros sueltos que no se destruyen hasta cerra el programa?

Tal como te lo he propuesto como lo que yo haría, es decir creando los punteros en el constructor del Form y destruyéndolos al final, al tiempo que tu función getSourceDestinyFromTask no crea el puntero sino que sólo rellena la lista pasada como parámetro, no quedan punteros sueltos. Se Crean con el Form y se destruyen con el mismo. No habrá problemas de memoria.

Se ejecuta una tarea (backup) pasando datos de C:\ a D:\ 30 Gigas duración 3horas
Se ejecuta otra tarea (mientras la primera sigue ejecutándose) pasando datos de C:\prueba a D:\prueba 10 Gigas duración 10 min.
La gran cuestión es: se afecta la primera tarea?


Ten en cuenta que cada Hilo que añadas consume recursos. Ca copia de archivos entretiene al disco y lentifica el sistema, sobre todo si trabajamos sobre el mismo disco y además es el del S.O., pero eso no tiene remedio. Sólo te queda que tu código de copia sea lo mas eficiente posible.

Las interferencias aparecerán si tratas de copiar el mismo archivo a la misma ruta el hilos diferentes y al mismo tiempo...


Saludos.
  • 0

#14 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 02:02

:)Espero que todo resulte como me cuentas entonces, de todos modos se te ocurre alguna idea de como resolver lo de la interferencia si se copia el mismo origen al mismo destino en diferentes hilos a la vez?
Un saludo y gracias.
  • 0

#15 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 02:22

alguna idea de como resolver lo de la interferencia si se copia el mismo origen al mismo destino en diferentes hilos a la vez?


La API CopyFile  usada para copiar devuelve false si no tuvo éxito. Puedes tratar de intentar la copia mas tarde...

También puedes levar una lista de las copias que fueron OK o de las erróneas, para  tratar de repetirlas...

Saludos.
  • 0

#16 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 02:34

gracias scafandra, me quedo con la idea de hacer una list de copias no me agrada mucho la idea de usar APIs, por desconocimiento...
  • 0

#17 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 11 agosto 2010 - 03:09

gracias scafandra, me quedo con la idea de hacer una list de copias no me agrada mucho la idea de usar APIs, por desconocimiento...


Bueno, la API CopyFile ya no es una desconocida para ti, te fué presentada en esta función:



cpp
  1. void __fastcall ThCopyFiles::Execute()
  2. {
  3.   String FileName;
  4.   for(int n=0; n < Strings->Count; n++){
  5.       FileName = Destino + String(Strings->Strings[n].c_str()+3);
  6.       CreatePath(ExtractFilePath(FileName).c_str());
  7.       CopyFile(Strings->Strings[n].c_str(), FileName.c_str(), false);
  8.       if(Terminated) return;
  9.   }
  10. }



:wink:


Saludos.

  • 0

#18 ifrit

ifrit

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 105 mensajes
  • LocationLa Habana, Cuba

Escrito 11 agosto 2010 - 03:32

:|Ni lo imaginaba, bueno entonces creo que esta mas sencillo el trabajo , si la estoy utilizando solo seria saber cuando devuelve true o false y volver a ejecutarlo si devuelve false no?
un millón de gracias scafandra.
  • 0




IP.Board spam blocked by CleanTalk.