2011-11-21 59 views
5

我正在嘗試創建一個將被自動刪除的臨時文件。在同一個過程中在同一個文件上創建2個FileStream

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

我想我已經嘗試了標誌的所有可能的組合,但我總是得到一個「的過程:

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

該文件將由第三方API,它還將創建一個FileStream使用不能訪問文件'XXX',因爲它正在被另一個進程使用...「

我做錯了什麼?有沒有辦法解決?

+0

您不能將文件流共享到第三方庫嗎? –

+0

首先創建臨時文件,然後關閉流。然後第三方API將能夠訪問它。完成作業後,刪除臨時文件。如果需要,請使用同步。 – kol

+0

我猜你不能在另一個進程中使用'FileAccess.Read,FileShare.Read',試着使用'FileAccess.ReadWrite,FileShare.ReadWrite'? – Cipi

回答

0

的問題是,你還有你創建開放的第一個流。您需要創建該文件,然後釋放它(關閉流),然後讓第三方API執行它,然後刪除該文件。將所有這些都包含在IDispoable的類中可能是一個很好的解決方案;在構造器中創建和釋放文件,方法包裝第三方工作,在dispose方法中刪除。

+0

他有開放流的問題,沒有注意到它。 – Cipi

+0

@Cipi ???我知道,我沒有提到任何關於文件內容的內容。 –

+0

我無法關閉流,因爲我使用標記** FileOptions.DeleteOnClose **創建了它。有了這個標誌,我相信即使進程崩潰了,文件也會被刪除。關閉流將刪除文件。這就是爲什麼我想保持它開放,直到API完成它的工作,然後只關閉流 –

2

根據文檔,是的。

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

摘錄:

閱讀:允許讀取該文件隨後打開。如果未指定此標誌,則在文件關閉之前,打開文件進行讀取的任何請求(通過此進程或其他進程)都將失敗。但是,即使指定了此標誌,訪問該文件仍可能需要其他權限。

0

您可以通過現有的流至3第三方的API,或者如果你想只只讀模式3,第三方阿比通過StreamReader例如

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

我有完全一樣的使用情況和遇到的同樣的問題。我嘗試使用(FileShare.ReadWrite | FileShare.Delete)這兩個流,它的工作原理。

+0

肯是在正確的軌道上。如果打開一個FileStream進行寫入並指定FileShare.Read,則打開第二個FileStream進行讀取,然後必須指定FileShare.ReadWrite以允許與「寫入」文件流(如第一個FileStream)共享。 –

0

僅當第三方API使用FileShare.ReadWrite或您的公開使用FileAccess.Read時,此調用序列纔可用。

您正在打開它的讀/寫,同時允許其他人也打開它的讀/寫。 第三方代碼試圖以只讀方式打開它,同時允許其他人也打開它,但只能以只讀方式打開它。由於您仍然可以讀寫,因此失敗。

假如你不能改變的第三方代碼,您將需要採取以下方式代替:

  1. 打開爲您當前所在的文件,但沒有DeleteOnClose標誌。
  2. 編寫任何需要閱讀其他代碼的內容。
  3. 關閉文件。(可能爲DeleteOnClose)。
  4. 調用第三方代碼。
  5. 做任何你想要的任何其他閱讀(但不寫)。
0

根據我的經驗,與FileOptions.DeleteOnClose開了FileStream無法通過將文件路徑到另一個FileStream無論FileShare價值被打開。

當您擁有所有代碼(顯然不是您的情況,對不起)DuplicateHandle可用於多次打開DeleteOnClose文件,即使是來自不同的進程。

下面是.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()); 
     } 
    } 
    } 
} 
相關問題