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 21-02-2007
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
Una Pregunta Teórica sobre Archivos UDT

Hola:

El siguiente programa funciona correctamente:

Código Delphi [-]
 
program TestFile;
{$APPTYPE CONSOLE}
uses
  SysUtils, StrUtils;
Type
TPrnCmd = Record
   ProcPrnCmd : array [0..40] of char;
   DatePrnCmd : array [0..12] of char;
   TimePrnCmd : array [0..12] of char;
   Status : array [0..30] of char;
   CRLF : array [0..1] of char;
end;
var
   i : integer;
   RegPrnCmd : TPrnCmd;
function LogPrnCmd(LogFile, ProcPrnCmd, StatusProc : String) : Boolean;
var
   i : integer;
   f: File of TPrnCmd;
   // RegPrnCmd : TPrnCmd;
   DateProc : String;
begin
   LogFile := GetCurrentDir + '\' + LogFile;
   AssignFile(f, LogFile);
   FileMode := fmOpenWrite ;
   if FileExists(LogFile) then
      Reset(f)
   else
      Rewrite(f);
   DateProc := FormatDateTime('dd/mm/yyyy',Date);
   StrPCopy(RegPrnCmd.ProcPrnCmd,ProcPrnCmd);
   StrPCopy(RegPrnCmd.DatePrnCmd,MidStr(DateProc,7,4) + '-' + MidStr(DateProc,4,2) + '-' + MidStr(DateProc,1,2));
   StrPCopy(RegPrnCmd.TimePrnCmd,FormatDateTime('hh:mm:ss',Time));
   StrPCopy(RegPrnCmd.Status,StatusProc);
   StrPCopy(RegPrnCmd.CRLF,chr(13)+chr(10));

   Seek(f, FileSize(f));
   Write(f,RegPrnCmd);
   CloseFile(f);
end;
begin
   for i := 1 to 10 do
      LogPrnCmd('TestFile.txt','Proc'+IntToStr(i),'Status'+IntToStr(i));
end.

La estructura UDT RegPrnCmd : TPrnCmd, esta definida a nivel global, y esta en la function LogPrnCmd, pero como comentario. Si se comenta la que esta a nivel global (RegPrnCmd) y se usa a nivel local, eliminando los carácteres de comentario, el programa da el error: "Project TestFile.exe raised exception class EInOutError with message I/O error 6. Process Stopped. Use Step or Run to continue.

La pregunta es: ¿Por que funciona si la declaración de RegPrnCmd, es a nivel global y falla si es declarada a nivel local?

Como dije anteriormente es una pregunta teórica, el programa ya funciona pero me gustaría aclarar la duda.

Gracias de antemano por toda la colaboración prestada.
Responder Con Cita
  #2  
Antiguo 23-02-2007
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
Usar GetCurrentDir no es normal en windows, ya que la carpeta activa puede ser diferente a donde está tu programa, usando ExtractFilePath(paramstr(0)) obtienes la ruta de tu ejecutable.

I/O error 6 es invalid handle (descriptor de archivos erróneno) muy probablemente porque la ruta currentdir+ LogFile no existe.


La pregunta no tiene cabida, ya que no tiene nada que ver con el error que está dando.

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.

Última edición por Lepe fecha: 23-02-2007 a las 14:25:08.
Responder Con Cita
  #3  
Antiguo 23-02-2007
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
Respuesta a Lepe

Hola:

Gracias por tu comentario.

Probe lo que me indicastes y el resultado es el mismo. ¿Sera posible que sea problema del compilador de Delphi o sera un error de concepto?

Dado que me comentas que es poco frecuente el uso de GetCurrentDir y me aconsejas usar ExtractFilePath(paramstr(0)) como una instrucción más estandar, pregunto: ¿Hay algún site ó libro que me recomiendes sobre buenas prácticas de programación en Delphi?

Nuevamente gracias por tus comentarios
Responder Con Cita
  #4  
Antiguo 24-02-2007
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
Estas funciones están en Delphi desde hace muchos años, dudo que sea un error del compilador, ya que se han usado intensivamente.

En principio no veo ningún fallo en el código, pero son tantas variables a tener en cuenta, que es difícil depurar.

Lo primero, haz un ShowMessage de LogFile para ver si hay 2 contrabarras en lugar de una y mirar el nombre y ruta del archivo. Intenta borrar el archivo primero para empezar desde cero, es muy común que en la primera ejecución el programa da un fallo porque no existe el archivo, después de parar el programa y volverlo a ejecutar, el fichero ya existe, por tanto funciona bien.

Mira lo que comenté en este otro hilo sobre rutas largas.

Un buen libro es la cara oculta de delphi 4 de Ians Marteens (antiguo pero muy útil y válido).

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #5  
Antiguo 24-02-2007
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
2007-02-24 Respuesta a Lepe

Hola:

Te comento:

1.- El programa funciona bien si la variable UDT es declarada a nivel global, si es declarada a nivel local da el error antes mencionado.

2.- Con la variable UDT declarada a nivel global, no importa si el archivo existe o si se crea en el proceso, es decir: No hay problemas con la composición del string de ruta del archivo.

3.- Si no hay errores de concepto o del string de ruta del archivo, entonces pregunto nuevamente: ¿Sera problema del compilador?

Te pongo un ejemplo de problemas del compilador: La función FormatMaskText no funciona como se indica en la ayuda de Delphi, (ver http://qc.borland.com/wc/qcmain.aspx?d=25360).

Este es uno de algunos funcionamientos atípicos en el compilador de Delphi que he encontrado durante mi trabajo, es por eso que creo en mi humilde opinión que el problema puede ser del compilador de Delphi, sin embargo admito que es difícil ímaginar que un compilador tan robusto y de tanta trayectoria como Delphi presente algún tipo de detalle.

Nota: Cuando digo compilador, me refiero a todo el lenguaje como tal, obviamente el problema puede ser de una unidad en particular, de un elemento del lenguaje en particular y no del compilador en si mismo, pero es una manera de generalizar el problema a efectos de explicación, dado que a ciencia cierta no puedo decir donde esta el problema con seguridad.

Nuevamente gracias por tus comentarios.
Responder Con Cita
  #6  
Antiguo 24-02-2007
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por nlsgarcia
El siguiente programa funciona correctamente
No. Realmente no funciona bien.

Cita:
Empezado por nlsgarcia
¿Por que funciona si la declaración de RegPrnCmd, es a nivel global y falla si es declarada a nivel local?
No funciona de ninguna manera, es sólo que has tenido suerte, pero, la programación no es cosa de suerte.

Cita:
Empezado por nlsgarcia
Como dije anteriormente es una pregunta teórica, el programa ya funciona pero me gustaría aclarar la duda
No, el programa aún no funciona y espero convencerte de ello para que no cargues con una bomba de tiempo que en algún momento te pueda estallar.

Es un problema interesante pues, a primera (y segunda) vista, no tiene sentido que sólo por cambiar el ámbito de la variable, deje de funcionar.

Ahora bien, puedes hacer que "funcione" usando la variable local simplemente declarándola antes del File of TPrnCmd, y no después:

Código Delphi [-]
function LogPrnCmd(LogFile, ProcPrnCmd, StatusProc : String) : Boolean;
var
   i : integer;
   RegPrnCmd : TPrnCmd;
   f: File of TPrnCmd;
   // RegPrnCmd : TPrnCmd;
   DateProc : String;

Bueno, pero eso no puede ser una solución. Seguiría siendo una cuestión de suerte.

El error que obtienes es I/O error 6, que corresponde, como te comentó Lepe, a Invalid File Handle. No es una cuestión de que el archivo no se encuentre, porque entonces obtendrías un error I/O error 2 (file not found) o 3 (path not found), pero no, tú obtienes un error que te dice que estás usando un descriptor de archivo incorrecto. Si hiciste una traza del programa te habrás dado cuenta que el error aparece en la línea:

Código Delphi [-]
Seek(f, FileSize(f));

Y, de hecho, el error lo genera FileSize. Pero si pones Seek(F, 28), el error lo genera Seek. Es decir, el error se genera cada vez que tratas de usar la variable F con alguna de las funciones de manejo de archivos. F es quien tiene el descriptor.

Ahora, ¿por qué está mal ese descriptor siendo que lo acabamos de crear con AssignFile? Algo, lo está dañando. Está claro que ni Reset ni Rewrite pueden dañarlo; como dice Lepe, esos procedimientos están ahí desde los tiempos de Matusalén (perdón, de Niklas Wirth).

Lo único que hay entre la creación del descriptor y su uso son las asignaciones con StrPCopy. Y, como dijera Sherlock Holmes, cuando todo lo demás se ha descartado, lo que quede, por improbable que esto sea, es la verdad.

Vayamos a la documentación de StrPCopy:

Cita:
StrPCopy copies Source into a null-terminated string Dest. It returns a pointer to Dest.

StrPCopy does not perform any length checking.

The destination buffer must have room for at least Length(Source)+1 characters.
¡Ajá! ¿Notas el +1? Ese +1 está porque necesitas espacio para el caracter nulo de terminación de la cadena.

Tu código no hace ninguna verificación de la longitud de las cadenas que copias, aunque me parece que con las primeras no hay problema porque los datos que pasas son cortos. Aún así tienes que agregar código para verficar.

Pero la última copia:

Código Delphi [-]
StrPCopy(RegPrnCmd.CRLF,chr(13)+chr(10));

es la que revienta todo. RegPrnCmd.CRLF está declarado como array [0..1] of char, esto es, dos caracteres, y tú necesitas espacio para 2 (#13#10) + 1 (#0) caracteres. Entonces, StrPCopy escribe el caracter de terminación #0 en la parte de memoria que hay después del espacio asignado a RegPrnCmd.

Según creo recordar, las variables locales se guardan en el stack o pila, así que, dependiendo del orden en que declares las variables, ese #0 sobreescribirá o no otra de las variables locales. Y una de esas variables, resulta ser la que contiene ¡el descriptor de archivo!

Si declaras la variable globalmente, no afecta al stack pues se localizan en regiones distintas de la memoria. Pero es sólo por suerte, suerte de que el caracter de más no esté sobrescribiendo algo que afecte el programa.

// Saludos

Última edición por roman fecha: 24-02-2007 a las 19:14:37.
Responder Con Cita
  #7  
Antiguo 24-02-2007
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
¡¡¡ Qué lección de maestría !!!

Saludos.
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #8  
Antiguo 24-02-2007
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
2007-02-24 Respuesta a Roman

Hola:

Gracias por tu análisis y por tus comentarios, el programa ya fue corregido.

Por favor analiza estos posibles errores de compilador y me comentas:

Problema con Rewrite:http://www.clubdelphi.com/foros/show...ma+con+Rewrite

La función FormatMaskText no funciona como se indica en la ayuda de Delphi, : http://qc.borland.com/wc/qcmain.aspx?d=25360)

Lepe me recomendo un excelente libro digital: El lado oscuro de Delphi 4, pregunto: ¿hay algún libro digital o site que me recomiendes sobre buenas practicas de programación en Delphi adicional a este?

Nuevamente Gracias.
Responder Con Cita
  #9  
Antiguo 25-02-2007
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Bueno, no hemos dicho que delphi o el compilador esté libre de errores. Pero el de FormatMaskText no es un problema del compilador, simplemente la función al parecer tiene fallos. Y el otro caso pues ¿qué decir? La verdad dudo mucho que el problema sea tal como lo describe; yo probé ese mismo código con y sin línea en blanco y con la misma versión de Delphi, y en ambos casos funciona bien. Tu caso era posible analizarlo porque estaba todo el código; en el otro caso habría que ver qué más hay que pueda estar afectando.

Pero, aunque seguramente delphi no está libre de fallos, lo importante aquí, en mi opinión, es como muchas situaciones que podríamos jurar que se deben a bugs, resultan tener explicación y se deben a fallos nuestros.

// Saludos
Responder Con Cita
  #10  
Antiguo 25-02-2007
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Por cierto- no lo he probado y por eso pregunto -¿no sería más sencillo si en lugar de declarar:

Código Delphi [-]
TPrnCmd = Record
   ProcPrnCmd : array [0..40] of char;
   DatePrnCmd : array [0..12] of char;
   TimePrnCmd : array [0..12] of char;
   Status : array [0..30] of char;
   CRLF : array [0..1] of char;
end;

lo hicieras así:

Código Delphi [-]
TPrnCmd = Record
   ProcPrnCmd : String[41];
   DatePrnCmd : String[13];
   TimePrnCmd : String[13];
   Status : String[31];
   CRLF : String[2];
end;

Según recuerdo, con strings de tamaño fijo no tienes problemas con los records y te permite hacer asignaciones directas en lugar de usar funciones como StrPCopy más propias de C que de Pascal.

// Saludos
Responder Con Cita
  #11  
Antiguo 25-02-2007
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
2007-02-24-2 Respuesta a Roman

Hola:

Si modifico el programa como tu me sugieres, tendria algo como esto:

Código Delphi [-]
 
program TestFile;
 {$APPTYPE CONSOLE}
uses
  SysUtils, StrUtils;
Type
TPrnCmd = Record
   ProcPrnCmd : String[41];
   DatePrnCmd : String[13];
   TimePrnCmd : String[13];
   Status : String[31];
   CRLF : String[2];
end;
var
   i : integer;
   RegPrnCmd : TPrnCmd;
function LogPrnCmd(LogFile, ProcPrnCmd, StatusProc : String) : Boolean;
var
   i : integer;
   f: File of TPrnCmd;
   DateProc : String;
   AuxStr : String;
   CRLF : String;
begin
   LogFile := GetCurrentDir + '\' + LogFile;
   AssignFile(f, LogFile);
   FileMode := fmOpenWrite ;
   if FileExists(LogFile) then
      Reset(f)
   else
      Rewrite(f);
   DateProc := FormatDateTime('dd/mm/yyyy',Date);
   CRLF := Chr(13) + Chr(10);
   RegPrnCmd.ProcPrnCmd := ProcPrnCmd;
   RegPrnCmd.DatePrnCmd := MidStr(DateProc,7,4) + '-' + MidStr(DateProc,4,2) + '-' + MidStr(DateProc,1,2);
   RegPrnCmd.TimePrnCmd := FormatDateTime('hh:mm:ss',Time);
   RegPrnCmd.Status := StatusProc;
   RegPrnCmd.CRLF :=CRLF;
   Seek(f, FileSize(f));
   Write(f,RegPrnCmd);
   CloseFile(f);
end;
begin
   for i := 1 to 10 do
      LogPrnCmd('TestFile.txt','Proc'+IntToStr(i),'Status'+IntToStr(i));
end.

Y la salida obtenida seria esta:

Proc1 2007-02-24 19:50:11 Status1 
Proc2 2007-02-24 19:50:11 Status2 
Proc3 2007-02-24 19:50:11 Status3 
Proc4 2007-02-24 19:50:11 Status4 
Proc5 2007-02-24 19:50:11 Status5 
Proc6 2007-02-24 19:50:11 Status6 
Proc7 2007-02-24 19:50:11 Status7 
Proc8 2007-02-24 19:50:11 Status8 
Proc9 2007-02-24 19:50:11 Status9 
Proc10 2007-02-24 19:50:11 Status10 

Es por el caracter , que no use el tipo String.

Gracias nuevamente por tus comentarios.
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
Pregunta Sobre el uso del DBGrid MARYLOSO Conexión con bases de datos 5 14-07-2005 17:19:03
Pregunta sobre BDE JorgeBec Conexión con bases de datos 1 18-03-2005 15:53:02
Pregunta sobre .net VolaRe .NET 10 14-04-2004 22:09:50
pregunta sobre Ms Sql ssaavedra MS SQL Server 1 09-01-2004 15:35:51
Pregunta sobre SplashScreen DarkByte Varios 2 14-09-2003 20:33:48


La franja horaria es GMT +2. Ahora son las 01:09:36.


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