PDA

Ver la Versión Completa : Propiedades de Ficheros


Lapiz_y_Papel
13-04-2006, 20:47:13
Antes de nada saludos a todos.
Y ahora al tema:

Me estoy iniciando en Delphi,(un poco de paciencia) y en estos momentos estoy con el tema de ficheros. Estoy escribiendo un programa en el que pretendo obtener las propiedades de un fichero que he seleccionado de un Tshelllistview linkado a un Tshelltreeview; obtener la ruta y extraer el nombre y la extension no me da problemas; lo tengo cuando deseo obtener su tamaño; el código que utilizo es el siguiente:


procedure TForm1.Button2Click(Sender: TObject);
var
security:tsecurityattributes;
hfile: integer;
fileinfo: tbyhandlefileinformation;
intermediate: tfiletime;
systemtime: tsystemtime;
filetype: dword;
ampm:string;
begin
Security.nLength:=SizeOf(TsecurityAttributes);
Security.bInheritHandle:=FALSE;
Hfile:=CreateFilePCharExtractFilenameShelllistView1.SelectedFolder.PathName)),
generic_read,0,@security,Open_existing,file_attribute_normal,0);
Form1.Enabled:=False;
Form2.Visible:=True;
Form2.Enabled:=True;
Form2.Label2.Caption:=(ShellListView1.SelectedFolder.PathName);
Form2.Label5.Caption:=ExtractFileName(ShellListView1.SelectedFolder.PathName);
Form2.Label6.Caption:=ExtractFileExt(ShellListView1.SelectedFolder.PathName);

Form2.Edit1.Text:=inttostr(getfilesize(hfile,nil));

Esta última línea es la que me da el problema: siempre obtengo el mismo tamaño de archivo:4294967295 independientemente del tamaño que tenga el archivo seleccionado. Tengo entendido que el registro TbyHandleFileinformation posee dos palabras:
nFileSizeHigh y nFilesizeLow del tipo DWORD pero no tengo ni idea de como manejarlas y ni mucho menos lograr un tipo entero que me de el tamaño real del fichero.

¿Alguien puede ayudarme con esto?
¿que otras formas existen de obtener las propiedades de un fichero?

Gracias de antemano.

Nota: utilizo la version de Delphi 2006

Sotrono
13-04-2006, 22:08:57
Hola, bienvenido al Club. Te recomiendo que leas la guia de estilo del foro.
La funcion FindFirst y FindNext te van a ser muy utiles para el manejo de archivos.

Bytes...

OSKR
16-04-2006, 16:13:17
FileSizeByName(ShellListView1.SelectedFolder.PathName);

Lapiz_y_Papel
16-04-2006, 20:43:08
FilesizebyName me da el siguiente error al compilar: Identificador no declarado; segun he leido tengo que declarar idglobal en la cláusula Uses
pero aún así me sigue dando el mismo error; ¿Que es lo que hago mal?.

No obstante he encontrado este código

http://www.delphi3000.com/articles/article_2686.asp

que funciona muy bién.




//========================================================
function GetFileSize(FileName: String): Integer;
var
FS: TFileStream;
begin
try
FS := TFileStream.Create(Filename, fmOpenRead);
except
Result := -1;
end;
if Result <> -1 then Result := FS.Size;
FS.Free;
end;
//========================================================

==========================================================
Example of use:
==========================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
ShowMessage(IntToStr(GetFileSize('c:\prova.pdf')));
end;
==========================================================
Saludos.

OSKR
16-04-2006, 20:48:44
Una vez q agregues la libreria (o unidad, no se como le digan) no deberia dar el error.
la otra manera q plasmas tambien es vàlida

Lepe
17-04-2006, 10:52:15
Deberías declarar el Resultado como Int64, por aquello de archivos grandes.

Saludos

Lapiz_y_Papel
17-04-2006, 13:15:32
Todas las respuestas me están siendo de gran ayuda.
Gracias a todos.

Por cierto,¿Donde puñetas encuentro la guía de estilo?.

Gracias otra vez.

Lapiz_y_Papel
17-04-2006, 15:16:35
En fin. El caso es que me gustaría comprender como delphi trata los ficheros via API-Windows.:confused:
He escrito el siguiente código al objeto de tratar el tipo

TByHandleFileInformation.

Según "Los Tomos de delphi: Núcleo del Api-Win32" ed. Danysoft 1999 viene definido de la siguiente forma:

TByHandleFileInformation = record
dwFileAttributes: DWORD;
ftCreationTime: TFileTime;
ftLastAccessTime: TfileTime;
ftLastWriteTime: TFileTime;
dwVolumeSerialNumber: DWORD;
nFileSizeHigh: DWORD;
nFileSizeLow: DWORD;
nNumberOfLinks: DWORD;
nFileIndexHigh: DWORD;
nFileIndexLow: DWORD;
end.


Pues bien, he escrito el siguiente código al objeto de comprobar el tipo:


procedure TForm1.Button3Click(Sender: TObject);

var

hfile: integer;
fileinfo: tbyhandlefileinformation;
tamaño1,tamaño2:dword;

begin

tamaño1:=0;
tamaño2:=0;

hfile:=CreateFile(PChar(ShelllistView1.SelectedFolder.PathName),
generic_read,0,@security,Open_existing,file_attribute_normal,0);

if (hfile=invalid_handle_value) then Label1.Caption:='Handle Invalido'
else Begin
getfileinformationbyhandle(hfile,fileinfo);
tamaño1:=fileinfo.nFileSizelow;
tamaño2:=fileinfo.nfilesizeHigh;
Label2.Caption:=inttostr(tamaño1);
Label3.Caption:=inttostr(tamaño2);
closehandle(hfile)
end;


tamaño1 siempre me da el valor 2.012.174.878
y tamaño2: 2.010.279.026 :eek:

mientras que con el código de http://www.delphi3000.com/articles/article_2686.asp

obtengo siempre el tamaño correcto.


¿Que es lo que está mal en el código anterior?

Los tipos están declarados como DWORD, igual que en el registro, las variables inicializadas, el Handle no me da error, etc, etc.

Gracias por vuestro valioso tiempo.

Saludos.

Lepe
17-04-2006, 18:53:21
No sé bien que estas usando, pero una carpeta no tiene tamaño, tienes que sumar el tamaño de todos los archivos que tiene dentro. Normalmente se usa una rutina recursiva.

Para hallar el tamaño exacto de un archivo sería:

var exacto : int64;
begin
exacto := nfilesizehigh * MAXCARDINAL + nfilesizeLow;

donde MAXCARDINAL es una constante declarada en la unidad sysutils.
El tamaño exacto viene dado en Bytes.

Saludos

Lapiz_y_Papel
17-04-2006, 20:46:55
No se bien a que te refieres cuando dices que no sabes bién lo que estoy usando; si te refieres al compilador utilizo Delphi 2006; si te refieres al código es tal y como lo escribí en el mensaje anterior; tengo un ShellTreeview linkado a un ShellListview y desde éste último selecciono un fichero en concreto.

Shelllistview.SelectedFolder.PathName me devuelve la ruta completa de "un" fichero, ¿No es asi?; de hecho si utilizo

extractfilename(shelllistview.selectedforlder.pathname) me devuelve el nombre del fichero seleccionado; ademas si fuera como tu dices...
if (hfile=invalid_handle_value) ¿no devolvería True?

No obstante probaré el código que me envías (en estos momentos no tengo tiempo).
¿Podrías decirme donde encuentro una buena referencia sobre sysutils?
¿Porqué razón es necesario multiplicar nfilesizehigh por MAXCARDINAL?
No se si todo esto es abusar mucho de vuestra paciencia, pero de todos modos muchas gracias.

Saludos.:D

Lepe
18-04-2006, 02:29:11
Reconozco que no he usado mucho los controles ShellTreeview y ShellListView, por tanto, al ver en tu codigo SelectedFolder.PathName, creía que el objeto seleccionado era una carpeta en lugar de un archivo.


Sobre sysutils, deberías tenerlo en el "uses" de tu formulario, es simplemente una unidad que tienes que usar para que reconozca la constante MAXCARDINAL.

El hecho de multiplicar por MAXCARDINAL, es por definición de la API de windows, no usan un tipo de datos Int64 (que es mucho mayor que un DWORD), así que dividen ese valor en 2 valores, la parte alta (filesizeHigh) y la parte baja (filesizeLow).

Imagina que queremos guardar un valor de 8 bits pero solo tenemos registros de 4 bits. En este caso queremos guardar el valor 130, la forma de dividirlo en dos partes sería así:

130 equivale en binario a: 10000010 , pero son 8 bits (8 digitos)

Como tenemos solo 4 bits, lo dividimos en 2 partes:
- por un lado la parte alta (los 4 bits de la izquierda) 1000
- y por el otro la parte baja (los 4 bits de la derecha) 0010

Si miras independientemente los valores, 1000 equivale a 8 en decimal, y 0010 equivale a 2 en decimal, que obviamente no es el 130 que queríamos guardar.

En este caso, el máximo número que se puede almacenar con 4 bits sería 2^4 - 1 , es decir 16 valores, desde el cero hasta el quince, para poder sacar el valor real, la formula a usar es:


parte_alta * 16 + parte_baja
8 * 16 + 2 = 130



Al aplicar la fórmula con el 8 y con el 2, si obtenemos el 130 que queríamos guardar.

Un número DWORD usa 32 bits; un Int64 usa 64 bits, justo el doble de bits, por tanto dividen el Int64 en dos DWORD, y no hay más remedio que usar la formula de marras ;).

Es un truco muy usado en la API de windows.

Saludos.

Lapiz_y_Papel
20-04-2006, 00:12:44
Gracias Lepe, ya veo que te has esmerado en tu respuesta.
Lamentablemente tengo problemas con el compilador, (se me cuelga al iniciarlo) y tengo que reinstalarlo. En cuanto lo haga probaré las cuestiones que me comentas.
:)

Lapiz_y_Papel
01-05-2006, 10:59:52
He intentado utilizar la variable MAXCARDINAL y me el siguiente error de compilacion:

[error]Unit1.pas(124):E2003 Undeclared identifier:'MAXCARDINAL' :mad:


Este es el código que utilizo:


unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, ComCtrls, ShellCtrls, StdCtrls;

type
........
........
.......
TForm1 = class(TForm)
Panel1: TPanel;
.......
.......
.......

procedure Button4Click(Sender: TObject);

private
{ Private declarations }
public
{ Public declarations }
end;

var
.........
.........
........

implementation
uses Unit2;
{$R *.dfm}

procedure TForm1.Button4Click(Sender: TObject);
begin

Edit1.Text:=inttostr(MAXCARDINAL)

end;


Mirando en en la ayuda de sysutils solo encuentro las variables:


<SPAN class=listedLink>

Lapiz_y_Papel
01-05-2006, 11:03:27
:mad: :mad: :mad:

La pregunt continúa:

He mirado en la ayuda y solo encuentro las variables de sysutils:

Falseboolstr
Trueboolstr

y las constantes:

Datedelta
Unixdatedelta

¿Ya no está declarada MAXCARDINAL en la version 2005?
Agradeceria cualquier respuesta.

Saludos: :)

Lepe
01-05-2006, 18:17:12
Pues tienes toda la razón, me equivoqué del todo :mad:

Es la constante MAXDWORD que realmente tambien guarda el máximo de un cardinal, ya que es el mismo tipo.

La unidad es Windows.

Saludos y lamento las molestias.

PD: Creo que me estoy oxidando un poco, igual es la vejez :rolleyes:

Lapiz_y_Papel
01-05-2006, 19:54:50
No te preocupes Lepe, agradezco tu ayuda. He buscado esa variable y efectivamente esta ahi; tiene el valor 4.294.967.295 ¿No es asi?.

De todos modos aún no consigo sacar nada de Delphi que funcione como es debido; todavía me queda un carro por aprender. :o

Gracias de Nuevo: :)