Ожидайте, пока файл не разблокирован в.NET

С традиционным для цикла

ArrayList<String> myArray = new ArrayList<>();

   for (int i = 0; i < myArray.size(); ) {
        String text = myArray.get(i);
        if (someCondition(text))
             myArray.remove(i);
        else 
             i++;
      }
93
задан Peter Mortensen 1 April 2011 в 08:16
поделиться

9 ответов

Это было ответом, который я дал на связанный вопрос :

    /// <summary>
    /// Blocks until the file is not locked any more.
    /// </summary>
    /// <param name="fullPath"></param>
    bool WaitForFile(string fullPath)
    {
        int numTries = 0;
        while (true)
        {
            ++numTries;
            try
            {
                // Attempt to open the file exclusively.
                using (FileStream fs = new FileStream(fullPath,
                    FileMode.Open, FileAccess.ReadWrite, 
                    FileShare.None, 100))
                {
                    fs.ReadByte();

                    // If we got this far the file is ready
                    break;
                }
            }
            catch (Exception ex)
            {
                Log.LogWarning(
                   "WaitForFile {0} failed to get an exclusive lock: {1}", 
                    fullPath, ex.ToString());

                if (numTries > 10)
                {
                    Log.LogWarning(
                        "WaitForFile {0} giving up after 10 tries", 
                        fullPath);
                    return false;
                }

                // Wait for the lock to be released
                System.Threading.Thread.Sleep(500);
            }
        }

        Log.LogTrace("WaitForFile {0} returning true after {1} tries",
            fullPath, numTries);
        return true;
    }
38
ответ дан Community 24 November 2019 в 06:19
поделиться

Я делаю это тот же путь как Gulzar, просто продолжаю пробовать циклом.

На самом деле я даже не беспокоюсь наблюдателем файловой системы. При опросе сетевого диска относительно новых файлов, как только минута является дешевой.

-1
ответ дан Jonathan Allen 24 November 2019 в 06:19
поделиться

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

while (true)
{
    try {
        stream = File.Open( fileName, fileMode );
        break;
    }
    catch( FileIOException ) {

        // check whether it's a lock problem

        Thread.Sleep( 100 );
    }
}
1
ответ дан harpo 24 November 2019 в 06:19
поделиться

От MSDN:

событие OnCreated генерируется, как только файл создается. Если файл будет скопирован или передан в наблюдаемый каталог, событие OnCreated будет сразу сгенерировано, сопровождаться одним или несколькими событиями OnChanged.

Ваш FileSystemWatcher мог быть изменен так, чтобы он не делал читать/переименовывать во время события "OnCreated", а скорее:

  1. Spanws поток, который запрашивает состояние файла, пока это не заблокировано (использование объекта FileInfo)
  2. , Перезванивает на службу обработать файл, как только это решает, что файл больше не блокируется и готов пойти
3
ответ дан Guy Starbuck 24 November 2019 в 06:19
поделиться

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

4
ответ дан Gulzar Nazim 24 November 2019 в 06:19
поделиться

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

  • Ftp два файла, но только наблюдают тот. Например, отправьте файлам important.txt и important.finish. Только наблюдайте за файлом конца, но обработайте txt.
  • FTP один файл, но переименовывают его, когда сделано. Например, отправьте important.wait и имейте отправителя, переименовывают его к important.txt по окончании.

Удачи!

5
ответ дан jason saldo 24 November 2019 в 06:19
поделиться

В большинстве случаев простой подход как предложенный @harpo будет работать. Можно разработать более сложный код с помощью этого подхода:

  • Находят все открытые дескрипторы для выбранного файла с помощью Подкласса SystemHandleInformation\SystemProcessInformation
  • класс WaitHandle для получения доступа к, он - внутренний дескриптор
  • Передача, найденная дескрипторами, обернутыми в разделенный на подклассы WaitHandle к WaitHandle. Метод WaitAny
2
ответ дан aku 24 November 2019 в 06:19
поделиться

Как насчет этого в качестве опции:

private void WaitOnFile(string fileName)
{
    FileInfo fileInfo = new FileInfo(fileName);
    for (long size = -1; size != fileInfo.Length; fileInfo.Refresh())
    {
        size = fileInfo.Length;
        System.Threading.Thread.Sleep(1000);
    }
}

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

-3
ответ дан 24 November 2019 в 06:19
поделиться

Я собрал вспомогательный класс для такого рода вещей. Это сработает, если вы контролируете все, что имеет доступ к файлу. Если вы ожидаете разногласий от множества других вещей, то это бесполезно.

using System;
using System.IO;
using System.Threading;

/// <summary>
/// This is a wrapper aroung a FileStream.  While it is not a Stream itself, it can be cast to
/// one (keep in mind that this might throw an exception).
/// </summary>
public class SafeFileStream: IDisposable
{
    #region Private Members
    private Mutex m_mutex;
    private Stream m_stream;
    private string m_path;
    private FileMode m_fileMode;
    private FileAccess m_fileAccess;
    private FileShare m_fileShare;
    #endregion//Private Members

    #region Constructors
    public SafeFileStream(string path, FileMode mode, FileAccess access, FileShare share)
    {
        m_mutex = new Mutex(false, String.Format("Global\\{0}", path.Replace('\\', '/')));
        m_path = path;
        m_fileMode = mode;
        m_fileAccess = access;
        m_fileShare = share;
    }
    #endregion//Constructors

    #region Properties
    public Stream UnderlyingStream
    {
        get
        {
            if (!IsOpen)
                throw new InvalidOperationException("The underlying stream does not exist - try opening this stream.");
            return m_stream;
        }
    }

    public bool IsOpen
    {
        get { return m_stream != null; }
    }
    #endregion//Properties

    #region Functions
    /// <summary>
    /// Opens the stream when it is not locked.  If the file is locked, then
    /// </summary>
    public void Open()
    {
        if (m_stream != null)
            throw new InvalidOperationException(SafeFileResources.FileOpenExceptionMessage);
        m_mutex.WaitOne();
        m_stream = File.Open(m_path, m_fileMode, m_fileAccess, m_fileShare);
    }

    public bool TryOpen(TimeSpan span)
    {
        if (m_stream != null)
            throw new InvalidOperationException(SafeFileResources.FileOpenExceptionMessage);
        if (m_mutex.WaitOne(span))
        {
            m_stream = File.Open(m_path, m_fileMode, m_fileAccess, m_fileShare);
            return true;
        }
        else
            return false;
    }

    public void Close()
    {
        if (m_stream != null)
        {
            m_stream.Close();
            m_stream = null;
            m_mutex.ReleaseMutex();
        }
    }

    public void Dispose()
    {
        Close();
        GC.SuppressFinalize(this);
    }

    public static explicit operator Stream(SafeFileStream sfs)
    {
        return sfs.UnderlyingStream;
    }
    #endregion//Functions
}

Он работает с использованием именованного мьютекса. Те, кто желает получить доступ к файлу, пытаются получить контроль над именованным мьютексом, который разделяет имя файла (с замененными '\' на '/'). Вы можете использовать Open (), который будет останавливаться до тех пор, пока мьютекс не станет доступным, или вы можете использовать TryOpen (TimeSpan), который пытается получить мьютекс на заданное время и возвращает false, если он не может быть получен в течение указанного промежутка времени. Это, скорее всего, следует использовать внутри блока using, чтобы гарантировать, что блокировки сняты должным образом, и поток (если он открыт) будет правильно удален, когда этот объект будет удален.

Я провел быстрый тест с ~ 20 действиями для выполнения различных операций чтения / записи файла и не обнаружил повреждений. Очевидно, что он не очень продвинутый, но он должен работать в большинстве простых случаев.

13
ответ дан 24 November 2019 в 06:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: