2012-12-19 6 views
12

Sul mio server ci sono alcuni file con Data di modifica 31/DEC/1979 (Non chiedermi il motivo). Quindi FileExists restituisce false.Problema con FileExists e Data di modifica

Sysutils.FileExists assomiglia a questo:

function FileAge(const FileName: string): Integer; 
var 
    Handle: THandle; 
    FindData: TWin32FindData; 
    LocalFileTime: TFileTime; 
begin 
    Handle := FindFirstFile(PChar(FileName), FindData); 
    if Handle <> INVALID_HANDLE_VALUE then 
    begin 
    Windows.FindClose(Handle); 
    if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then 
    begin 
     FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime); 
     if FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi, 
     LongRec(Result).Lo) then Exit; 
    end; 
    end; 
    Result := -1; 
end; 

function FileExists(const FileName: string): Boolean; 
begin 
    Result := FileAge(FileName) <> -1; 
end; 

La mia domanda è, perché la funzione dipende FileAge in primo luogo? Non è la seguente riga sufficiente ?:

if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then 
    // Yes the file exists! 

O anche sulla base di attributi di file:

function MyFileExists(const Name: string): Boolean; 
var 
    R: DWORD; 
begin 
    R := GetFileAttributes(PChar(Name)); 
    Result := (R <> DWORD(-1)) and ((R and FILE_ATTRIBUTE_DIRECTORY) = 0); 
end; 
+0

Era per gestire i sistemi di archiviazione che creava implicitamente in lettura. So che esistevano, ma sono d'accordo se riesco a trovare qualche documentazione ora. – david

risposta

11

Le versioni moderne di Delphi implementano FileExists in linea di massima allo stesso modo come il codice fa. L'implementazione ha una gestione extra per i collegamenti simbolici, ma è sostanzialmente identica alla tua versione.

C'è una sfumatura interessante nella moderna implementazione di Delphi. Se la chiamata a GetFileAttributes restituisce INVALID_FILE_ATTRIBUTES, il codice non viene immediatamente salvato. Invece lo fa:

LastError := GetLastError; 
Result := (LastError <> ERROR_FILE_NOT_FOUND) and 
    (LastError <> ERROR_PATH_NOT_FOUND) and 
    (LastError <> ERROR_INVALID_NAME) and ExistsLockedOrShared(Filename); 

E l'attuazione di ExistsLockedOrShared utilizza FindFirstFile e un assegno del FILE_ATTRIBUTE_DIRECTORY su dwFileAttributes. Ciò indica che GetFileAttributes può avere esito negativo quando il file esiste, ma è bloccato. Ma quello FindFirstFile può riuscire in tale scenario. Questo è ragionevole perché FindFirstFile utilizza i metadati del file anziché i dati memorizzati nel file stesso.

È difficile dire perché il codice sia così come è nelle versioni precedenti. Penso che sia debole. Personalmente sostituirò FileExists con una versione migliore, usando un hook di codice. Per esempio: Patch routine call in delphi

Come sempre, c'è un articolo Raymond Chen sul tema: Superstition: Why is GetFileAttributes the way old-timers test file existence?

+2

+1 come tutti i veterani stavo anche usando 'GetFileAttributes' con il mio D5 per verificare se il file esiste. ma non sapeva del problema di blocco/condivisione. Potete per favore pubblicare l'implementazione completa del codice per 'FileExists'? :) Questo è quello che ho trovato per [D2009] (http://embarcadero.newsgroups.archived.at/public.delphi.language.delphi.win32/200903/0903173087.html). – kobik

+1

@kobik Non riesco a pubblicare la fonte Delphi. Ma userei semplicemente l'approccio 'FindFirstFile' e test' (FindData.dwFileAttributes e FILE_ATTRIBUTE_DIRECTORY) = 0'. Potrebbe non essere il più veloce, ma aggira i problemi con i file bloccati. Se vuoi essere carino, il 'LastError' che controlla la risposta è sufficiente per completare il resto. –

+0

Grazie a @David. Interessante ho trovato [un'altra versione] (http://www.delphimaster.ru/cgi-bin/forum.pl?id=1268982928&n=5&toprint=1) che imposta 'SetErrorMode (SEM_FAILCRITICALERRORS)' (e lo ripristina) prima chiamare il codice, per evitare di ottenere una finestra di errore critico se ad esempio si espelle un'unità CDROM e si prova a verificare se il file esiste. – kobik

4

A giudicare dalla realizzazione 'moderna' di FileExists (che non fa uso FileAge e anche ottimizzato e in grado di seguire i collegamenti simbolici per verificare se collegata esistono file):

  • la prima variante ((FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0) è OK;
  • la seconda variante (GetFileAttributes) potrebbe non riuscire se il file è bloccato o condiviso.
1

Per il vecchio versios di Delphi è possibile scaricare la libreria di codici Jedi. Ha la seguente implementazione (oltre a molte altre classi e funzioni utili):

function FileExists(const FileName: string): Boolean; 
{$IFDEF MSWINDOWS} 
var 
    Attr: Cardinal; 
{$ENDIF MSWINDOWS} 
begin 
    if FileName <> '' then 
    begin 
    {$IFDEF MSWINDOWS} 
    // FileGetSize is very slow, GetFileAttributes is much faster 
    Attr := GetFileAttributes(Pointer(Filename)); 
    Result := (Attr <> $FFFFFFFF) and (Attr and FILE_ATTRIBUTE_DIRECTORY = 0); 
    {$ELSE ~MSWINDOWS} 
    // Attempt to access the file, doesn't matter how, using FileGetSize is as good as anything else. 
    Result := FileGetSize(FileName) <> -1; 
    {$ENDIF ~MSWINDOWS} 
    end 
    else 
    Result := False; 
end; 
+2

È lo stesso codice fornito nella domanda –

+1

Penso che sia anche una buona risposta poiché conferma che JCL usa anche GetFileAttributes come volevo fare. – ZigiZ