2009-03-11 16 views
10

In molti dei miei apps Ho codice simile al seguente:Delphi: Perché a volte ricevo un errore I/O 103 con questo codice?

if ForceDirectories(ExtractFilePath(lLogName)) then 
    begin 
    AssignFile(lLog, lLogName); 
    try 
     if FileExists(lLogName) then 
     Append(lLog) 
     else 
     Rewrite(lLog); 
     Writeln(lLog, lLogLine); 
    finally 
     {$I-}CloseFile(lLog);{$I+} 
    end; 
    end; 

In una sola applicazione, la prima volta che provo a eseguire questo ho sempre ottenere un errore 103 un'eccezione I/O sulla linea con l'accodamento dichiarazione (il file esiste prima di chiamare questo). Tutti i tentativi successivi all'operazione funzioneranno comunque, fino a quando non riavvio l'app.

Tutti i documenti che ho trovato su questo errore finora indicato che questo sarebbe neanche essere causato chiamando CloseFile senza previa Reset o Rewrite (Append in genere non è menzionato) o se il file era in uso da un altro processo. Poiché l'eccezione si verifica prima della chiamata a CloseFile, ovviamente non poteva essere la prima.

Ho già provato a inserire uno Reset subito dopo lo AssignFile per buona misura, ma poi ottengo l'eccezione su quella linea.

Non c'è anche nessun'altra applicazione che acceda apertamente quel file. Dico "apertamente" perché ho un leggero sospetto che l'anti-virus (TrendMicro nel mio caso) potrebbe essere il cuplrit qui (quindi forse il file è in uso). Se quello fosse davvero il problema, quale sarebbe il modo migliore per aggirarlo? Hard-codifica una richiamata automatica in realtà non sentire come una soluzione pulita per me ...


Un altro caso in cui a volte ottengo l'errore 103 è questo codice, che io uso per creare un file vuoto (o più spesso per svuotare un file esistente):

AssignFile(lFile, AFileName); 
try 
    Rewrite(lFile); 
finally 
    CloseFile(lFile); 
end; 

In questo caso è molto più difficile da riprodurre. Succede molto meno spesso. Il più delle volte questo sembra accadere alla prima esecuzione dopo aver ricompilato l'applicazione. Potrebbe questo essere di nuovo l'anti-virus che si frappone? Ho sempre visto questo accadere sulla mia macchina di sviluppo e non ho mai ottenuto un rapporto da un cliente. Come nel caso del primo scenario, ciò si verifica solo una volta per sessione applicativa (se non del tutto). I tentativi successivi sono sempre positivi.

Qualche suggerimento per un approccio diverso, potenzialmente più sicuro per la creazione di file vuoti o lo svuotamento di quelli esistenti?

risposta

2

Non vedo cosa c'è di sbagliato con il tentativo automatico. Non vedo che tu possa fare qualsiasi altra cosa. Se qualche altro processo sta leggendo il file, allora Append/Rewrite avrà esito negativo. E poiché il file è un log, c'è una buona probabilità che qualcosa, come un visualizzatore di log o un editor di testo, sia da leggere nel momento in cui si tenta di aprirlo.

Provare ad aprire il file alcune volte con un ritardo tra un tentativo e l'altro prima di fallire definitivamente. Potresti usare un backoff esponenziale se volessi essere fantasioso.

3

Oltre all'antivirus, può anche essere indicizzato software o software di gestione file, come Google Desktop. Tuttavia, il vero problema è che il messaggio di errore non aiuta a risolvere il problema. Suggerisco di riscrivere il codice per utilizzare TFileStream, al solo scopo di migliorare i messaggi di errore.

+1

+1 Sostengo fortemente l'uso di TFileStream. Una volta effettuato l'interruttore, non vorrai tornare indietro. – skamradt

+0

Sì, usando TFileStream sarete in grado di lavorare con file più grandi di 2 GB. Su tali file 'append()' e 'writeln()' non possono funzionare ('IOResult <> 0' o eccezione). –

0

Il codice di esempio dovrebbe funzionare in generale, quegli errori sembrano essere errori di accesso. Per rilevare il caso, è possibile provare a disabilitare TrendMicro e verificare se il problema persiste.

1

La tua app è multi-threaded? Una volta ho avuto lo stesso problema di questo quando il codice di registrazione è stato chiamato simultaneamente da entrambi i thread. In tal caso, utilizzare una TCriticalSection per controllare l'accesso.

+0

Le app in questione sono multi-thread ma questo codice viene sempre eseguito dal thread principale. Un buon suggerimento, tuttavia. –

3

In generale, è consigliabile aprire il file prima di provare ..infine:

if fileexists then 
    append(..) 
else 
    rewrite(..); 
try 
    // do something with the file 
finally 
    CloseFile(..); 
end; 

e

AssignFile(lFile, AFileName); 
Rewrite(lFile); 
CloseFile(lFile); 

(provare finalmente non ha alcun senso nel caso precedente)

In caso contrario, chiudere il file potrebbe non riuscire perché non poteva essere aperto e questo sarebbe mascherare il vero errore.

Ma non credo che questo sia il problema qui.

+1

Hai ragione. AssignFile in realtà non acquisisce alcuna risorsa, quindi è troppo presto per inserire un blocco try-finally subito dopo quella chiamata. Inserisci solo try-finally dopo Aggiungi, Ripristina o Riscrivi: quelle sono le funzioni che aprono un file. –

+0

Sì, sembra ragionevole. Non l'avevo ancora visto fino a quel momento ... –

+0

Impossibile aggiungere e riscrivere fallire? Penso che possa –

1

Si potrebbe osservare un errore di deviazione da qualcos'altro compilato in uno stato $ I-?

0

Se ho capito bene, l'assegnazione dei file fallisce. Sei sicuro che i FileCheck siano nel momento in cui chiami AssignFile? Questo è abbastanza insolito, ma si potrebbe verificare questo utilizzando:

{$IFOPT I-} 

if IOResult <> 0 then 
begin 
    // Error handling 
end; 
{$ENDIF} 

sono d'accordo sull'uso di TFileStream (o qualcosa, ma la funzione di accesso ai file a basso livello), invece. Questo è critico per le prestazioni e può essere un grosso problema quando si passa a Unicode.

10

Ok, è passato più di un anno, ma aggiungerò il mio commento a questo, in quanto spiega perché questo sta accadendo.

Ho avuto lo stesso identico problema in un'applicazione multi-thread con codice quasi identico al frammento sopra e avevo sezioni critiche che proteggevano il codice.

Il problema si è verificato più facilmente quando un'operazione di registrazione ha subito seguito un'altra. La seconda operazione fallirebbe per la ragione di cui sopra.

Ho pensato che fosse anche un software anti-virus, ma l'errore si è verificato su una macchina e non sull'altra, dove entrambi avevano installato Norton 360. La macchina con il problema era nuova di zecca Windows 7 e quella senza era Windows XP. Un collega ha avuto anche il problema di eseguire il sistema con una macchina virtualizzata di Windows Vista senza l'installazione di un programma antivirus.

Quindi la mia domanda era: "perché questa macchina XP era così diversa?".

Per uno, non era vergine, e questa è la risposta sembra:

blocco opportunistico e NT cache stati spenti. La maggior parte degli sviluppatori Delphi (maturi) saprà che quando si utilizza BDE, questi vengono disattivati ​​al fine di mantenere l'integrità del file DBF e DB in situazioni multiutente. Queste impostazioni non erano disabilitate sulle macchine più recenti perché non sviluppiamo più i file di dati di Paradox!

Il caching in scrittura differita sembra lasciare un blocco di lettura/scrittura sul file fino a quando il sistema operativo ha fatto il suo lavoro, che potrebbe essere diversi millisecondi dopo.

Quindi, nel mio caso, il secondo evento del registro veniva bloccato dal primo.

Ok, non sto suggerendo di disattivare il blocco opportunistico + NT Caching. Uno dei motivi principali per cui ci siamo allontanati da BDE è stato quello di evitare di convincere i clienti a sperimentare tali impostazioni. Quindi, ci sono quattro soluzioni pratiche:

1) Per riprovare per un periodo di tempo accettabile, come indicato da dangph.

2) per aprire il file quando l'applicazione lo carica e lo tiene aperto per tutta la durata dell'applicazione. Non è così utile se stai eseguendo più istanze dell'applicazione.

3) Posizionare con cautela un (1) sonno prima del codice di registrazione e sperare che sia sufficiente per il rilascio del blocco. Ma questo rischia di rallentare il tuo sistema se stai facendo molti log.

o 4) Fai una prova ... eccetto il tuo codice. Ma probabilmente avrai la certezza di perdere il 100% dei secondi messaggi (riferiti al mio caso).

0

odio di Windows ... vedere perché:

Questo è il codice che risolve il problema di riscrittura (senza messaggi):

AssignFile(MyFileHandler,RouteToWritableExistantFile); 
try 
    ReWrite(MyFileHandler); // This sometimes fails 
except 
     ReWrite(MyFileHandler); // When prior fails, this runs OK 
end; 

Sì, è assurdo ... se fallisce ReWrite , the do a Rewrite ... ma funziona per me al 100% delle volte.

I DEBUG problema che mettere un sacco di ShowMessage ... aveva un po 'di immaginazione dopo aver provato le cose non assurde (file è stato precedentemente oppened, ecc) ... cosa succederebbe se provassi il ReWrite due volte? Sorpresa ... se prima fallisce, il secondo tentativo funziona!

So che è assurdo, ma funziona!

sapevo che perché stavo mettendo un sacco di messaggi, proprio come questo:

  ShowMessage('1: - pre - AssignFile - '); 
AssignFile(MyFileHandler,RouteToWritableExistantFile); 
      ShowMessage('2: - post - AssignFile - '); 
try 
      ShowMessage('3: - pre - ReWrite - '); 
    ReWrite(MyFileHandler); // This sometimes fails 
      ShowMessage('4: - pre - ReWrite - '); 
except 
      ShowMessage('5: - pre - ReWrite - '); 
     ReWrite(MyFileHandler); // When prior fails, this allways runs OK (it is absurd, but works) 
      ShowMessage('6: - pre - ReWrite - '); 
end; 

e ho avuto due theese secuences di messaggi:

  • 1,2,3,4 quando riscrittura fisrt funziona
  • 1,2,3,5,6 quando riscrittura fisrt fallisce, notare che la struttura 6, quindi secondo riscrittura ha lavorato

Spero che questo aiuti gli altri a non impazzire !!!

P.D .: Lo stesso problema si verifica in Reimposta ... ora lo incapsulare sempre in tale tentativo ... tranne blocco e sbarazzarsi del problema!

0

Ciao. Probabilmente è troppo tardi per rispondere alla domanda originale, ma voglio aggiungere il mio pezzo, e nonostante non sia una risposta diretta alla domanda originale, voglio contribuire, poiché penso che possa aiutare alcuni altri a cercare questo tipo di risposta.

Ho ottenuto questa stessa risposta di errore, ma in un software completamente diverso, in particolare l'analizzatore EIS, più volte cercavo di aprire un file, ma un po 'di tempo avrebbe potuto essere stato aperto. Questo era curioso per me, così ho preso per internet. E davvero, per quanto improbabile, sembrava (perché il programma di mediazione è piuttosto piccolo), ho trovato una simile chiamata d'errore.Stavo scuoiando le risposte di cui sopra e quella che ha due controlli con il tic di controllo verde, ho seguito giusto, solo intuitivamente, ed è così che: quando ho aperto il file in un altro programma, non mi lascerà andare aprilo come file nell'analizzatore EIS.

Quindi la conclusione generale: quando è stato aperto un file in un programma, non vi permetterà di aprire altrove e si ottiene un errore di I/O Error 103.

PS: Un po 'audace e lassista e facile conclusione (senza aver letto correttamente (ma non ho avuto tempo, scusa) le risposte di cui sopra), ma spero che tu abbia il punto. :) Saluti.

0

Inavvertitamente ho chiuso CloseFile due volte e ho avuto questo errore.

Problemi correlati