2011-11-21 15 views
5

Sto provando a creare un file temporaneo che verrà automaticamente eliminato.Creare 2 FileStream sullo stesso file nello stesso processo

stream = new FileStream(
      tmpFilePath, 
      FileMode.OpenOrCreate, 
      FileAccess.ReadWrite, 
      FileShare.ReadWrite, 
      4096, 
      FileOptions.DeleteOnClose|FileOptions.RandomAccess 
      ); 

Questo file verrà utilizzato da un API 3rd party che sarà anche creare un FileStream:

stream = new FileStream(
      tmpFilePath, 
      FileMode.Open, 
      FileAccess.Read, 
      FileShare.Read); 

Credo di aver provato tutte le possibili combinazioni di bandiere ma ottengo sempre "il processo impossibile accedere al file "XXX" perché è utilizzato da un altro processo ... "

Sto facendo qualcosa di sbagliato? C'è un modo per aggirare?

+0

non è possibile condividere il flusso di file nella libreria di terze parti? –

+0

Creare prima il file temporaneo e chiudere lo stream. Quindi l'API di terze parti sarà in grado di accedervi. Dopo aver completato il suo lavoro, eliminare il file temporaneo. Usa la sincronizzazione, se necessario. – kol

+0

Immagino che non puoi usare 'FileAccess.Read, FileShare.Read' in un altro processo, prova a usare' FileAccess.ReadWrite, FileShare.ReadWrite'? – Cipi

risposta

0

Il problema è che avete ancora il primo flusso si è creato aperto. È necessario creare il file, quindi rilasciarlo (chiudere lo stream), quindi fare in modo che l'API di terze parti funzioni, quindi eliminare il file. Racchiudere tutto questo in una classe che è IDSoable potrebbe essere una buona soluzione; crea e rilascia il file nel contructor, avvolgi il metodo del lavoro di terze parti, elimina nel metodo dispose.

+0

Ha problemi ad aprire lo stream, non avendo notato in esso. – Cipi

+0

@Cipi ??? Lo so, non ho detto nulla sul contenuto del file. –

+0

Non riesco a chiudere lo stream perché l'ho creato con il flag ** FileOptions.DeleteOnClose **. Con questo flag, sono sicuro che anche se il processo si blocca, il file verrà eliminato. La chiusura dello stream eliminerà il file. Ecco perché voglio tenerlo aperto fino a quando l'API non ha fatto il suo lavoro e quindi solo chiudere lo stream –

2

Secondo la documentazione, sì.

http://msdn.microsoft.com/en-us/library/system.io.fileshare.aspx

Estratto:

Leggi: consente la successiva apertura del file per la lettura. Se questo flag non viene specificato, qualsiasi richiesta di apertura del file per la lettura (tramite questo processo o un altro processo) avrà esito negativo fino alla chiusura del file. Tuttavia, anche se questo flag è specificato, potrebbero essere necessarie ulteriori autorizzazioni per accedere al file.

0

È possibile passare flusso esistente per Api partito 3-rd, o se volete solo leggere solo modo per la 3-rd Api partito passare StreamReader esempio

using (var stream = new FileStream("trace.txt", FileMode.OpenOrCreate,FileAccess.ReadWrite)) 
    { 
     using (var anotherStream = new StreamReader(stream)) 
     { 
      //magic here 
     } 
    } 
2

Ho esattamente lo stesso caso d'uso e incontrare il stesso problema. Quello che provo è usare (FileShare.ReadWrite | FileShare.Delete) per entrambi i flussi e funziona.

+0

Ken è sulla strada giusta. Se un FileStream viene aperto per la scrittura e specifica FileShare.Read, il secondo FileStream viene aperto per la lettura, quindi deve specificare FileShare.ReadWrite per consentire la condivisione con flussi di file di "scrittura" (come ad esempio il primo FileStream). –

0

Questa sequenza di chiamate funziona solo se l'API di terze parti utilizza FileShare.ReadWrite o gli usi aperti FileAccess.Read.

Si sta aprendo in lettura/scrittura, consentendo agli altri di aprirlo anche in lettura/scrittura. Il codice di terze parti sta tentando di aprirlo in sola lettura, consentendo agli altri di aprirlo, ma solo in sola lettura. Dal momento che hai ancora aperto read-write, questo fallisce.

Supponendo che non è possibile modificare il codice di terze parti, è necessario adottare il seguente schema, invece:

  1. Aprire il file come ci si trova, ma senza la bandiera DeleteOnClose.
  2. Scrivi qualsiasi contenuto di cui hai bisogno l'altro codice da leggere.
  3. Chiudere il file.
  4. Opzionalmente riaprirlo con FileAccess.Read (ed eventualmente DeleteOnClose).
  5. Chiama il codice di terze parti.
  6. Esegui qualsiasi altra lettura (ma non la scrittura) che desideri.
0

Nella mia esperienza, un FileStream aperta con FileOptions.DeleteOnClose non può essere aperto facendo passare il percorso del file ad un altro FileStream indipendentemente dal valore FileShare.

Quando si possiede tutto il codice (chiaramente non è il tuo caso, mi dispiace) DuplicateHandle può essere utilizzato per aprire un file DeleteOnClose più volte, anche da processi diversi.

Ecco alcuni esempi di codice per .NET 4.5.1.

using System; 
using System.Diagnostics; 
using System.IO; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Windows.Forms; 
using Microsoft.Win32.SafeHandles; 

namespace Example 
{ 
    public static class DuplicatedHandleExample 
    { 
    [DllImport("kernel32.dll")] 
    private static extern bool DuplicateHandle(
     SafeFileHandle hSourceProcessHandle, 
     IntPtr hSourceHandle, 
     SafeFileHandle hTargetProcessHandle, 
     out SafeFileHandle lpTargetHandle, 
     UInt32 dwDesiredAccess, 
     bool bInheritHandle, 
     UInt32 dwOptions); 

    [DllImport("kernel32.dll")] 
    private static extern SafeFileHandle OpenProcess(
     UInt32 dwDesiredAccess, 
     bool bInheritHandle, 
     int dwProcessId); 

    private const UInt32 PROCESS_DUP_HANDLE = 0x0040; 

    private const UInt32 DUPLICATE_SAME_ACCESS = 0x0002; 

    public static void CreateFileInProcessA() 
    { 
     try 
     { 
     // open new temp file with FileOptions.DeleteOnClose 
     string tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D")); 
     using (FileStream fs = new FileStream(tempFilePath, FileMode.CreateNew, 
      FileAccess.ReadWrite, FileShare.Read | FileShare.Write | FileShare.Delete, 
      4096, FileOptions.DeleteOnClose)) 
     { 
      // put a message in the temp file 
      fs.Write(new[] { (byte)'h', (byte)'i', (byte)'!' }, 0, 3); 
      fs.Flush(); 

      // put our process ID and file handle on clipboard 
      string data = string.Join(",", 
      Process.GetCurrentProcess().Id.ToString(), 
      fs.SafeFileHandle.DangerousGetHandle().ToString()); 

      Clipboard.SetData(DataFormats.UnicodeText, data); 

      // show messagebox (while holding file open!) and wait for user to click OK 
      MessageBox.Show("Temp File opened. Process ID and File Handle copied to clipboard. Click OK to close temp file."); 
     } 
     } 
     catch (Exception ex) 
     { 
     MessageBox.Show(ex.ToString()); 
     } 
    } 

    public static void OpenFileInProcessB() 
    { 
     try 
     { 
     // get process ID and file handle from clipboard 
     string data = (string)Clipboard.GetData(DataFormats.UnicodeText); 
     string[] dataParts = data.Split(','); 
     int sourceProcessId = int.Parse(dataParts[0]); 
     IntPtr sourceFileHandle = new IntPtr(Int64.Parse(dataParts[1])); 

     // get handle to target process 
     using (SafeFileHandle sourceProcessHandle = 
      OpenProcess(PROCESS_DUP_HANDLE, false, sourceProcessId)) 
     { 
      // get handle to our process 
      using (SafeFileHandle destinationProcessHandle = 
      OpenProcess(PROCESS_DUP_HANDLE, false, Process.GetCurrentProcess().Id)) 
      { 
      // duplicate handle into our process 
      SafeFileHandle destinationFileHandle; 
      DuplicateHandle(sourceProcessHandle, sourceFileHandle, 
       destinationProcessHandle, out destinationFileHandle, 
       0, false, DUPLICATE_SAME_ACCESS); 

      // get a FileStream wrapper around it 
      using (FileStream fs = new FileStream(destinationFileHandle, FileAccess.ReadWrite, 4096)) 
      { 
       // read file contents 
       fs.Position = 0; 
       byte[] buffer = new byte[100]; 
       int numBytes = fs.Read(buffer, 0, 100); 
       string message = Encoding.ASCII.GetString(buffer, 0, numBytes); 

       // show messagebox (while holding file open!) and wait for user to click OK 
       MessageBox.Show("Found this message in file: " + message + Environment.NewLine + 
       "Click OK to close temp file"); 
      } 
      } 
     } 
     } 
     catch (Exception ex) 
     { 
     MessageBox.Show(ex.ToString()); 
     } 
    } 
    } 
} 
Problemi correlati