2011-11-21 33 views
5

Tôi đang cố tạo một tệp tạm thời sẽ tự động bị xóa.Tạo 2 FileStream trên cùng một tệp trong cùng một quá trình

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

Tập tin này sẽ được sử dụng bởi một API bên thứ 3 mà cũng sẽ tạo ra một FileStream:

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

Tôi nghĩ rằng tôi đã thử tất cả sự kết hợp có thể có của lá cờ nhưng tôi luôn có được một "Quá trình này không thể truy cập tệp 'XXX' do tệp đang được sử dụng bởi một quy trình khác ... "

Tôi có làm gì sai không? Có cách nào không?

+0

bạn không thể chia sẻ luồng tệp với thư viện của bên thứ ba phải không? –

+0

Tạo tệp tạm thời trước và đóng luồng. Sau đó, API của bên thứ ba sẽ có thể truy cập vào nó. Sau khi hoàn thành công việc, xóa tệp tạm thời. Sử dụng đồng bộ hóa, nếu cần. – kol

+0

Tôi đoán bạn không thể sử dụng 'FileAccess.Read, FileShare.Read' trong một quá trình khác, hãy thử sử dụng' FileAccess.ReadWrite, FileShare.ReadWrite'? – Cipi

Trả lời

0

Vấn đề là bạn vẫn có luồng đầu tiên bạn đã mở. Bạn cần phải tạo tập tin, sau đó phát hành nó (đóng dòng), sau đó có API bên thứ 3 làm công việc của nó, sau đó xóa các tập tin. Bao bọc tất cả điều này trong một lớp học là IDispoable có thể là một giải pháp tốt đẹp; tạo và phát hành tập tin trong contructor, phương pháp bọc công việc của bên thứ 3, xóa trong phương pháp vứt bỏ.

+0

Anh ấy có vấn đề khi mở luồng, không cần chú ý đến nó. – Cipi

+0

@Cipi ??? Tôi biết, tôi không nói gì về nội dung của tập tin. –

+0

Tôi không thể đóng luồng vì tôi đã tạo luồng bằng cờ ** FileOptions.DeleteOnClose **. Với lá cờ này, tôi chắc chắn rằng ngay cả khi quá trình này bị treo, tệp sẽ bị xóa. Đóng luồng sẽ xóa tệp. Đó là lý do tại sao tôi muốn giữ nó mở cho đến khi API đã thực hiện công việc và sau đó chỉ đóng luồng –

2

Theo tài liệu, có.

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

Trích:

đọc: Cho phép mở tiếp theo của tập tin để đọc. Nếu cờ này không được chỉ định, bất kỳ yêu cầu nào để mở tệp để đọc (bằng quy trình này hoặc quy trình khác) sẽ không thành công cho đến khi tệp được đóng. Tuy nhiên, ngay cả khi cờ này được chỉ định, vẫn có thể cần thêm quyền truy cập để truy cập tệp.

0

Bạn có thể vượt qua dòng hiện có để Api bên 3 rd, hoặc nếu bạn muốn chỉ chế độ chỉ đọc cho 3 thứ Api bên vượt qua StreamReader dụ

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

tôi có chính xác cùng một vụ án sử dụng và gặp cùng một vấn đề. Những gì tôi cố gắng đang sử dụng (FileShare.ReadWrite | FileShare.Delete) cho cả hai dòng và nó hoạt động.

+0

Ken đang đi đúng hướng. Nếu một FileStream được mở để viết và chỉ định FileShare.Read, thì FileStream thứ hai được mở để đọc thì nó phải chỉ định FileShare.ReadWrite để cho phép chia sẻ với các luồng tập tin "viết" (chẳng hạn như FileStream đầu tiên). –

0

Chuỗi cuộc gọi này sẽ chỉ hoạt động nếu API của bên thứ ba sử dụng FileShare.ReadWrite hoặc sử dụng mở của bạn FileAccess.Read.

Bạn đang mở nó đọc/ghi, trong khi cho phép người khác cũng mở nó đọc/ghi. Mã của bên thứ ba đang cố gắng mở nó chỉ đọc, trong khi cho phép những người khác cũng mở nó, nhưng chỉ là chỉ đọc. Vì bạn vẫn có nó mở đọc-ghi, điều này không thành công.

Giả sử rằng bạn không thể thay đổi mã của bên thứ ba, bạn sẽ cần phải áp dụng các mô hình sau đây thay vì:

  1. Mở tập tin như bạn hiện đang có, nhưng nếu không có sự DeleteOnClose cờ.
  2. Viết bất kỳ nội dung nào bạn cần đọc mã khác.
  3. Đóng tệp.
  4. Tùy chọn mở lại bằng FileAccess.Read (và có thể là DeleteOnClose).
  5. Gọi mã của bên thứ ba.
  6. Thực hiện bất kỳ việc đọc nào khác (nhưng không viết) mà bạn muốn.
0

Theo kinh nghiệm của tôi, một FileStream mở với FileOptions.DeleteOnClose không thể mở được bằng cách thông qua các đường dẫn tập tin để FileStream khác không phụ thuộc vào giá trị FileShare.

Khi bạn sở hữu tất cả mã (rõ ràng không phải trường hợp của bạn, xin lỗi) DuplicateHandle có thể được sử dụng để mở tệp DeleteOnClose nhiều lần, ngay cả từ các quy trình khác nhau.

Dưới đây là một số mã ví dụ cho .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()); 
     } 
    } 
    } 
} 
Các vấn đề liên quan