Процесс не может получить доступ к файлу, потому что он используется другим процессом - PullRequest
1 голос
/ 02 февраля 2012

У меня два сервиса. 1-клиент 2-сервер. Обе службы общаются через сокет. Клиент содержит наблюдателя файловой системы. Всякий раз, когда наблюдатель файловой системы обнаруживает новый файл в указанной папке, он устанавливает соединение с сервером и отправляет файл на сервер. Сервер прослушивает определенный порт, принимает запрос, получает файл и сохраняет данные в БД. А затем отправляет сообщение об успехе / ошибке клиенту.

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

Любая помощь будет высоко оценена.

Код клиента:

namespace WindowsService1
{
public partial class Client : ServiceBase
{
    string hostIPAddress = string.Empty;
    string processedFilePath = string.Empty;
    int hostPort;
    Socket socketClient;
    IPEndPoint remoteEndPoint;
    FileStream fs;

    public PCMParserClient()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        hostIPAddress = ConfigurationManager.AppSettings["HostIP"];
        hostPort = int.Parse(ConfigurationManager.AppSettings["HostPort"]);
        //File system watcher
        FsWatcher.Path = ConfigurationManager.AppSettings["FileWatcherPath"];
        processedFilePath = ConfigurationManager.AppSettings["ProcessedFilePath"];
    }

    protected override void OnStop()
    {
    }

    private void FsWatcher_Created(object sender, System.IO.FileSystemEventArgs e)
    {
        try
        {
            socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);               
            IPAddress remoteIPAddress = IPAddress.Parse(hostIPAddress);
            remoteEndPoint = new IPEndPoint(remoteIPAddress, hostPort);
            //Establish the connection to server
            socketClient.Connect(remoteEndPoint);
            EventLog.WriteEntry(e.Name+"before");

                **//the below line generates teh exception for 2nd time onwards**
                 using (fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
                 {
                     EventLog.WriteEntry("1");
                     //Convert the file name in form of byte
                     byte[] fileNameByte = Encoding.ASCII.GetBytes(e.Name);
                     EventLog.WriteEntry(e.Name);

                     //4- to store the filename length(as int - 4bytes)
                     //8- to store the file content length(as long take 8 bytes)
                     int totalLength = 4 + fileNameByte.Length + 8;

                     //Clientdata[] reprents the data to sent to the server 
                     //which represent the file details
                     byte[] clientData = new byte[totalLength];
                     byte[] fileNameLength = BitConverter.GetBytes(fileNameByte.Length);
                     byte[] fileContentLength = BitConverter.GetBytes(fs.Length);

                     //Copy all the data ClientData array
                     fileNameLength.CopyTo(clientData, 0);
                     fileNameByte.CopyTo(clientData, 4);
                     fileContentLength.CopyTo(clientData, 4 + fileNameByte.Length);

                     //Send the data to server
                     socketClient.Send(clientData);

                     int byteRead = 0;
                     int bytesToRead = (int)fs.Length;

                     while (bytesToRead > 0)
                     {
                         byte[] data = new Byte[1500];
                         byteRead = bytesToRead > 1500 ? 1500 : bytesToRead;
                         int n = fs.Read(data, 0, byteRead);

                         //Send the data to server
                         socketClient.Send(data);
                         bytesToRead -= n;
                     }

                     fs.Flush();
                     //fs.Close();
                     //fs.Dispose();
                 }


                //Code block to get the success/failure message from server
                byte[] message = new byte[5];
                int msg = socketClient.Receive(message);

                else if (Encoding.ASCII.GetString(message).Contains("Error"))
                {
                    throw new Exception("Error occured while processing the file " + e.Name);
                }

        }
        catch (SocketException ex)
        {
            ExceptionLogger.LogException(ex);
        }
        catch (IOException ex)
        {
            ExceptionLogger.LogException(ex);
        }
        catch (Exception ex)
        {
            ExceptionLogger.LogException(ex);
        }
        finally
        {
            if (socketClient != null && socketClient.Connected)
            {
                socketClient.Close(); 
            }
        }
    }
}

}

Код сервера:

namespace PCMParserService
{
public partial class ParserServer : ServiceBase
{
    Socket serverSocket = null;
    public Timer timer1;
    IPEndPoint ipEndPoint;

    public HL7ParserService()
    {
        InitializeComponent();
        timer1 = new Timer(1000);
        timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
    }

    void timer1_Elapsed(object sender, ElapsedEventArgs e)
    {
        Socket handler = null;
        try
        {
            // The program is suspended while waiting for an incoming connection.
            // This is a synchronous TCP application
            handler = serverSocket.Accept();

            byte[] fileDetails = new byte[1500];
            //Recieve the file details
            handler.Receive(fileDetails);
            int fileNameLength = BitConverter.ToInt32(fileDetails, 0);
            string fileName = Encoding.ASCII.GetString(fileDetails, 4, fileNameLength);
            EventLog.WriteEntry(fileNameLength.ToString(), System.Diagnostics.EventLogEntryType.Information);
            int fileLength = BitConverter.ToInt32(fileDetails, 4 + fileNameLength);

            filePath = ConfigurationManager.AppSettings["ProcessedDirectory"];

            FileStream fs = new FileStream(filePath + fileName, FileMode.Create, FileAccess.Write);
            int byteRead = 0;

            while (byteRead < fileLength)
            {
                byte[] data = new Byte[1500];
                //Recieve the data and write to the file
                int r = handler.Receive(data);
                fs.Write(data, 0, r);
                byteRead += r;
            }
            fs.Flush();
            fs.Close();
            fs.Dispose();


            //-Code to Parse text file and save to db
            FileStream fileStream = new FileStream(filePath + fileName, FileMode.Open, FileAccess.Read);
            StreamReader sr = new StreamReader(fileStream);
            ///Code   
            fileStream.Close();
            fileStream.Dispose();
            sr.Close();
            sbMessage.Append("</Message>");
            saveFileDetails(sbMessage.ToString());

            //-- End of File Parsing code
            handler.Send(Encoding.ASCII.GetBytes("Done"));
        }
        catch (SocketException ex)
        {
            ExceptionLogger.LogException(ex, "Error occured while processing the file + " + filePath);
            handler.Send(Encoding.ASCII.GetBytes("Error"));
        }
        catch (IOException ex)
        {
            ExceptionLogger.LogException(ex, "Error occured while processing the file + " + filePath);
            handler.Send(Encoding.ASCII.GetBytes("Error"));
        }
        catch (SqlException ex)
        {
            ExceptionLogger.LogException(ex, "Error occured while processing the file + " + filePath);
            handler.Send(Encoding.ASCII.GetBytes("Error"));
        }
        catch (Exception ex)
        {
            ExceptionLogger.LogException(ex, "Error occured while processing the file + " + filePath);
            handler.Send(Encoding.ASCII.GetBytes("Error"));
        }
    }

    protected override void OnStart(string[] args)
    {
        try
        {
            //The port on which the server listens
            ipEndPoint = new IPEndPoint(IPAddress.Any, 8030);

            //Defines the kind of socket we want :TCP
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //Bind the socket to the local end point(associate the socket to local end point)
            serverSocket.Bind(ipEndPoint);

            //listen for incoming connection attempt
            // Start listening, only allow 100 connection to queue at the same time
            serverSocket.Listen(100);

            timer1.Start();
        }
        catch (SocketException ex)
        {
            ExceptionLogger.LogException(ex, string.Empty);
        }
        catch (Exception ex)
        {
            ExceptionLogger.LogException(ex, string.Empty);
        }
    }

    protected override void OnStop()
    {
        timer1.Stop();
    }

    protected override void OnPause()
    {
        timer1.Stop();
    }

    protected override void OnContinue()
    {
        timer1.Start();
    }

    protected override void OnShutdown()
    {
        timer1.Stop();
    }

}
}

Ответы [ 2 ]

2 голосов
/ 02 февраля 2012

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

ПараметрыЧтобы смягчить это, включите:

  • Наличие задержки после уведомления перед обработкой файла
  • Обработка файла немедленно, но помещение любых файлов, которые приводят к «Процесс не может получить доступ кфайл. Он используется другим процессом "в очередь для периодической повторной попытки.

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

0 голосов
/ 02 февраля 2012

Также следует помнить, что вы можете открыть файл с указанием типа доступа к нему нескольких объектов (что может иметь или не иметь значения в вашем случае).

Итак,вместо записи:

FileStream fileStream = new FileStream(filePath + fileName, 
                                       FileMode.Open, 
                                       FileAccess.Read);   

Вы можете попробовать добавить параметр FileShare:

FileStream fileStream = new FileStream(filePath + filename,
                                       FileMode.Open, 
                                       FileAccess.Read, 
                                       FileShare.Read))

, указав соответствующий FileShare flag, вы можете получить доступ к файлу, не дожидаясь его закрытия.Например, в строке выше, FileShare.Read:

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

...