2012-02-21 7 views
12

Ok, quindi ho cercato in molti posti la risposta a questa domanda, ma sono aperto a tutti i collegamenti se ho perso qualcosa di ovvio.Il pantano delle eccezioni legate all'apertura di un FileStream

Sono interessato a produrre messaggi di errore ragionevoli quando tentano di aprire un determinato file, ma per qualsiasi motivo il programma non può accedere a quel file. Vorrei distinguere tra i seguenti casi:

  • Il file è stato bloccato da un altro processo in modo tale che questo processo non può scrivere su di esso.
  • L'utente non dispone dei privilegi di accesso appropriati per scrivere sul file (come in, le autorizzazioni utente, come visualizzato nella schermata Proprietà di un file in Esplora risorse, non concedere all'utente il permesso di scrittura)
  • Il il file richiede il permesso "elevato" per accedere al file.

Sto usando un oggetto FileStream. Ho esaminato lo msdn documentation for instantiating a FileStream e non è affatto chiaro per me quale eccezione fa cosa per quanto sopra e come distinguere tra di essi. Ammetto che la mia esperienza con la programmazione di Windows è limitata, quindi potrei mancare qualcosa di ovvio. Le mie scuse se è così.

+1

C'è una differenza tra gli ultimi 2 casi che si desidera controllare? Immagino (anche se non hanno provato) che entrambi avrebbero lanciato un 'SecurityException' dove il primo caso avrebbe lanciato una' IOException'. –

+0

@ M.Babcock: In un certo senso, gli ultimi due casi non sono molto diversi. Tuttavia, l'utente deve (in generale) fare cose molto diverse per ottenere l'accesso al file. Per il secondo caso, potrebbe essere necessario richiedere che un altro utente dia loro il permesso. Per il 3 ° caso, hanno bisogno di "Esegui come amministratore" o forse spostare il file fuori dalla directory "Programmi" (anche se il motivo per cui dovrebbe essere lì non lo so). Vorrei aiutare l'utente a sapere cosa devono fare per ottenere l'accesso al file. – skybluecodeflier

+0

Ancora una volta, potrei mostrare la mia ignoranza del sistema operativo Windows nel mio precedente commento: sono aperto alla correzione se la mia interpretazione non è corretta. – skybluecodeflier

risposta

5

Ecco cosa si potrebbe fare:

1) Si potrebbe verificare se si dispone dei diritti di accesso al file prima di si tenta di accedere al file. Da this SO thread, ecco un metodo che dovrebbe restituire true se l'utente ha diritti Write (ad esempio quando si fa clic con il pulsante destro del mouse su un file -> proprietà -> sicurezza). Questo copre il vostro punto (2) per i privilegi di accesso unappropriated (si noti che non v'è forse più robusto/a prova di errore qualcosa per ottenere queste informazioni che il codice qui sotto):

public static bool HasWritePermissionOnFile(string path) 
{ 
    bool writeAllow = false; 
    bool writeDeny = false; 

    FileSecurity accessControlList = File.GetAccessControl(path); 
    if (accessControlList == null) 
    { 
     return false; 
    } 

    var accessRules = accessControlList.GetAccessRules(true, true, typeof(SecurityIdentifier)); 
    if (accessRules == null) 
    { 
     return false; 
    } 

    foreach (FileSystemAccessRule rule in accessRules) 
    { 
     if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) 
     { 
      continue; 
     } 

     if (rule.AccessControlType == AccessControlType.Allow) 
     { 
      writeAllow = true; 
     } 
     else if (rule.AccessControlType == AccessControlType.Deny) 
     { 
      writeDeny = true; 
     } 
    } 

    return writeAllow && !writeDeny; 
} 

2) Non cercare di istanziare la vostra FileStream , e le eccezioni di cattura:

try 
{ 
    string file = "..."; 
    bool hasWritePermission = HasWritePermissionOnFile(file); 
    using (FileStream fs = new FileStream(file, FileMode.Open)) 
    { 
    } 
} 
catch (UnauthorizedAccessException ex) 
{ 
    // Insert some logic here 
} 
catch (FileNotFoundException ex) 
{ 
    // Insert some logic here 
} 
catch (IOException ex) 
{ 
    // Insert some logic here 
} 

Nel tuo caso (3) (file richiede l'elevazione), UnauthorizedAccessException viene generata.

Nel tuo caso (1) (il file è bloccato da un altro processo), viene generato IOException. È quindi possibile controllare l'HRESULT dell'eccezione per maggiori dettagli:

catch (IOException ex) 
{ 
    // Gets the HRESULT 
    int hresult = Marshal.GetHRForException(ex); 

    // See http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx 
    // for system error code 
    switch (hresult & 0x0000FFFF) 
    { 
     case 32: //ERROR_SHARING_VIOLATION 
      Console.WriteLine("File is in use by another process"); 
      break; 
    } 
} 

Ora si dovrebbe essere in grado di distinguere i tuoi 3 casi d'uso.

+0

Hmm. Questo ha senso, lo metterò alla prova. Anche se non penso che sarei in grado di fidarmi unicamente della soluzione 1 che hai specificato qui, a causa della possibilità di condizioni di gara. Cioè, a) Il mio processo controlla per vedere se può accedere al file, b) qualche altro processo apre il file (o cambia permessi, ecc.), C) il mio processo prova ad aprire il file e fallisce/diventa irritabile/etc. – skybluecodeflier

+0

In realtà potrebbe esistere una condizione di competizione solo per caso (2) (privilegi di accesso non appropriati) se l'utente perde i diritti tra il controllo 'HasWritePermissionOnFile' e la chiamata' new FileStream'. Se si verifica, verrà generata un'eccezione 'UnauthorizedAccessException', quindi sarai ancora in grado di sapere che" c'è un problema di accesso ". Potresti quindi chiamare 'HasWritePermissionOnFile' all'interno del blocco' catch (UnauthorizedAccessException) 'per garantire l'eccezione quando generata a causa di un problema di elevazione. – ken2k

+0

Ha, sembra che sarebbe solo spostare la condizione di gara nel blocco catch per l'eccezione UnauthorizedAccessException. Anche se non sono sicuro che sia possibile evitarlo. O c'è? Funziona sicuramente in condizioni normali. Grazie! – skybluecodeflier