Создайте 2 FileStream для того же файла в том же процессе - PullRequest
6 голосов
/ 21 ноября 2011

Я пытаюсь создать временный файл, который будет автоматически удален.

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

Этот файл будет использоваться сторонним API, который также создаст FileStream:

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

Я думаю, что попробовал все возможные комбинации флагов, но всегда получаюa «Процесс не может получить доступ к файлу« XXX », поскольку он используется другим процессом ...»

Я что-то не так делаю?Есть ли способ обойти?

Ответы [ 7 ]

3 голосов
/ 21 ноября 2011

Согласно документации, да.

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

Выдержка:

Чтение: позволяет последующее открытие файла для чтения. Если этот флаг не указан, любой запрос на открытие файла для чтения ( с помощью этого процесса или другого процесса) не будет выполнен, пока файл не будет закрыт. Однако даже если этот флаг указан, для доступа к файлу могут потребоваться дополнительные разрешения.

2 голосов
/ 04 ноября 2015

У меня точно такой же вариант использования, и я столкнулся с той же проблемой. Я пытаюсь использовать (FileShare.ReadWrite | FileShare.Delete) для обоих потоков, и это работает.

0 голосов
/ 13 апреля 2016

По моему опыту, FileStream, открытый с помощью FileOptions.DeleteOnClose, нельзя открыть, передав путь к файлу другому 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());
      }
    }
  }
}
0 голосов
/ 09 декабря 2015

Эта последовательность вызовов будет работать, только если сторонний API использует FileShare.ReadWrite, или ваш open использует FileAccess.Read.

Вы открываете его для чтения / записи, в то время как другие также могут открывать его для чтения/записывать.Сторонний код пытается открыть его только для чтения, в то же время позволяя другим открывать его, но только для чтения.Поскольку он все еще открыт для чтения и записи, это не работает.

Предполагая, что вы не можете изменить сторонний код, вам нужно будет принять следующий шаблон:

  1. Откройте файл как есть, но без флага DeleteOnClose.
  2. Напишите любой контент, который вам нужен для прочтения другого кода.
  3. Закройте файл.
  4. При необходимости повторно откройте его с помощью FileAccess.Read (и, возможно, DeleteOnClose).
  5. Позвоните стороннему коду.
  6. Сделайте любое другое чтение (но не запись), которое вы хотите.
0 голосов
/ 21 ноября 2011

Вы можете передать существующий поток стороннему Api, или если вы хотите, чтобы режим только для чтения для стороннего Api проходил StreamReader экземпляр

    using (var stream = new FileStream("trace.txt", FileMode.OpenOrCreate,FileAccess.ReadWrite))
    {
        using (var anotherStream = new StreamReader(stream))
        {
            //magic here
        }
    }
0 голосов
/ 21 ноября 2011

Проблема в том, что у вас все еще открыт первый созданный вами поток.Вам нужно создать файл, затем освободить его (закрыть поток), затем заставить сторонний API выполнить свою работу, а затем удалить файл.Заключение всего этого в класс IDispoable может быть хорошим решением;создайте и отпустите файл в конструкторе, методом обертывания сторонней работы, удалите в методе dispose.

0 голосов
/ 21 ноября 2011

Звучит так, как будто вы хотите использовать файл с отображенной памятью в качестве метода для совместного использования одного файла с несколькими процессами.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...