Подождите, пока файл не будет полностью записан

Когда файл создан (FileSystemWatcher_Created) в одном каталоге я копирую его в другой. Но когда я создаю большой (& gt; 10 МБ) файл, он не может скопировать файл, потому что он начинает копировать уже, когда файл еще не закончил создание ...
Это вызываетCannot copy the file, because it's used by another process быть воспитанным. ; (
Любая помощь?

class Program
{
    static void Main(string[] args)
    {
        string path = @"D:\levan\FolderListenerTest\ListenedFolder";
        FileSystemWatcher listener; 
        listener = new FileSystemWatcher(path);
        listener.Created += new FileSystemEventHandler(listener_Created);
        listener.EnableRaisingEvents = true;

        while (Console.ReadLine() != "exit") ;
    }

    public static void listener_Created(object sender, FileSystemEventArgs e)
    {
        Console.WriteLine
                (
                    "File Created:\n"
                   + "ChangeType: " + e.ChangeType
                   + "\nName: " + e.Name
                   + "\nFullPath: " + e.FullPath
                );
        File.Copy(e.FullPath, @"D:\levan\FolderListenerTest\CopiedFilesFolder\" + e.Name);
        Console.Read();
    }
}
 levi11 июн. 2012 г., 16:38
Я нашел ответ здесь извините [Эта проблема решена в StackOverFlow] [1] [1]:stackoverflow.com/questions/1406808/…
 Adrian Carneiro31 мар. 2014 г., 14:35
возможный дубликатIs there a way to check if a file is in use?

Ответы на вопрос(9)

Итак, быстро просмотрев некоторые из этих и других подобных вопросов, я отправился на веселую погоню сегодня днем, пытаясь решить проблему с двумя отдельными программами, использующими файл в качестве метода синхронизации (а также сохранения файла). Немного необычная ситуация, но она определенно выдвинула для меня проблемы с проверкой «заблокирован ли файл», а затем откройте его, если он не «заблокирован». подход.

Проблема заключается в следующем: файл можетbecome заблокирован между временем, когда вы его проверяете, и временем, когда вы фактически открываете файл. Это действительно трудно отследить спорадическийCannot copy the file, because it's used by another process ошибка, если вы ее тоже не ищете.

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

Здесь код использует File.Copy, но он работает так же хорошо с любыми статическими методами класса File: File.Open, File.ReadAllText, File.WriteAllText и т. Д.

/// <param name="timeout">how long to keep trying in milliseconds</param>
static void safeCopy(string src, string dst, int timeout)
{
    while (timeout > 0)
    {
        try
        {
            File.Copy(src, dst);

            //don't forget to either return from the function or break out fo the while loop
            break;
        }
        catch (IOException)
        {
            //you could do the sleep in here, but its probably a good idea to exit the error handler as soon as possible
        }
        Thread.Sleep(100);

        //if its a very long wait this will acumulate very small errors. 
        //For most things it's probably fine, but if you need precision over a long time span, consider
        //   using some sort of timer or DateTime.Now as a better alternative
        timeout -= 100;
    }
}

Another small note on parellelism: Это синхронный метод, который блокирует поток как во время ожидания, так и во время работы с потоком. Это самый простой подход, но если файл остается заблокированным в течение длительного времени, ваша программа может перестать отвечать. Пареллизм - слишком большая тема, чтобы вдаваться в подробности (и количество способов, которыми вы можете настроить асинхронное чтение / запись, довольно нелепо), но вот один из способов, которым он может быть разбит на части.

public class FileEx
{
    public static async void CopyWaitAsync(string src, string dst, int timeout, Action doWhenDone)
    {
        while (timeout > 0)
        {
            try
            {
                File.Copy(src, dst);
                doWhenDone();
                break;
            }
            catch (IOException) { }

            await Task.Delay(100);
            timeout -= 100;
        }
    }

    public static async Task<string> ReadAllTextWaitAsync(string filePath, int timeout)
    {
        while (timeout > 0)
        {
            try {
                return File.ReadAllText(filePath);
            }
            catch (IOException) { }

            await Task.Delay(100);
            timeout -= 100;
        }
        return "";
    }

    public static async void WriteAllTextWaitAsync(string filePath, string contents, int timeout)
    {
        while (timeout > 0)
        {
            try
            {
                File.WriteAllText(filePath, contents);
                return;
            }
            catch (IOException) { }

            await Task.Delay(100);
            timeout -= 100;
        }
    }
}

И вот как это можно использовать:

public static void Main()
{
    test_FileEx();
    Console.WriteLine("Me First!");
}    

public static async void test_FileEx()
{
    await Task.Delay(1);

    //you can do this, but it gives a compiler warning because it can potentially return immediately without finishing the copy
    //As a side note, if the file is not locked this will not return until the copy operation completes. Async functions run synchronously
    //until the first 'await'. See the documentation for async: https://msdn.microsoft.com/en-us/library/hh156513.aspx
    CopyWaitAsync("file1.txt", "file1.bat", 1000);

    //this is the normal way of using this kind of async function. Execution of the following lines will always occur AFTER the copy finishes
    await CopyWaitAsync("file1.txt", "file1.readme", 1000);
    Console.WriteLine("file1.txt copied to file1.readme");

    //The following line doesn't cause a compiler error, but it doesn't make any sense either.
    ReadAllTextWaitAsync("file1.readme", 1000);

    //To get the return value of the function, you have to use this function with the await keyword
    string text = await ReadAllTextWaitAsync("file1.readme", 1000);
    Console.WriteLine("file1.readme says: " + text);
}

//Output:
//Me First!
//file1.txt copied to file1.readme
//file1.readme says: Text to be duplicated!

Это старая ветка, но я добавлю некоторую информацию для других людей.

У меня возникла аналогичная проблема с программой, которая записывает PDF-файлы, иногда на рендеринг уходит 30 секунд, что соответствует периоду, в течение которого мой класс watcher_FileCreated ожидает перед копированием файла.

Файлы не были заблокированы.

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

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

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

Когда это «в другой раз»? Я не помню, когда FileSystemWatcher отправлял несколько событий на файл - проверьте это, вам может быть достаточно просто проигнорировать событие и дождаться другого. Если нет, вы всегда можете установить время и перепроверить файл за 5 секунд.

Из документации дляFileSystemWatcher:

The OnCreated event is raised as soon as a file is created. If a file is being copied or transferred into a watched directory, the OnCreated event will be raised immediately, followed by one or more OnChanged events.

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

Что-то вроде (неполное; перехват определенных исключений, инициализация переменных и т. Д.):

    public static void listener_Created(object sender, FileSystemEventArgs e)
    {
        Console.WriteLine
                (
                    "File Created:\n"
                   + "ChangeType: " + e.ChangeType
                   + "\nName: " + e.Name
                   + "\nFullPath: " + e.FullPath
                );
        try {
            File.Copy(e.FullPath, @"D:\levani\FolderListenerTest\CopiedFilesFolder\" + e.Name);
        }
        catch {
            _waitingForClose.Add(e.FullPath);
        }
        Console.Read();
    }

    public static void listener_Changed(object sender, FileSystemEventArgs e)
    {
         if (_waitingForClose.Contains(e.FullPath))
         {
              try {
                  File.Copy(...);
                  _waitingForClose.Remove(e.FullPath);
              }
              catch {}
         }
   }
 levi11 июн. 2012 г., 16:50
это довольно хороший способ, но он мне нужен сразу, поэтому я поставил IsFileReady в то время, и он работает сейчас

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

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

public static bool IsFileClosed(string filename)
{
    try
    {
        using (var inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None))
        {
            return true;
        }
    }
    catch (IOException)
    {
        return false;
    }
}
 01 окт. 2014 г., 05:26
Почему отрицательный голос?
 12 янв. 2016 г., 19:49
Что возвращает этот код, если вы столкнулись с исключением, которое не является исключением IOException?
 13 янв. 2016 г., 21:00
Если File.Open выдает исключение, отличное от IOException, этот метод не возвращает значение. Вызывающий абонент обязан проверить наличие любых исключений, не связанных с вводом-выводом, которые могут возникнуть:msdn.microsoft.com/en-us/library/y973b725(v=vs.110).aspx

вам нужно дождаться окончания создания файла. Один из способов сделать это - проверить, все ли еще используется файл. Пример этого можно найти здесь:Есть ли способ проверить, используется ли файл?

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

public static void listener_Created()
{
   while CheckFileInUse()
      wait 1000 milliseconds

   CopyFile()
}

Очевидно, вы должны защитить себя от бесконечногоwhile на всякий случай приложение владельца никогда не снимает блокировку. Кроме того, возможно, стоит проверить другие события изFileSystemWatcher Вы можете подписаться на. Там может быть событие, которое вы можете использовать, чтобы обойти всю эту проблему.

потому что это сработало для меня. Я использовал задержки, циклы, все, что мог придумать.

У меня было окно проводника Windows открытой папки. Я закрыл это, и все работало как очарование.

Я надеюсь, что это помогает кому-то.

 03 февр. 2016 г., 10:17
так что теперь ваше приложение падает, если у пользователя открыт этот каталог?

Когда файл записывает в двоичном формате (побайтово-байтово), создайте решения FileStream и выше. Не работает, поскольку файл готов и обработан для каждого байта, поэтому в этой ситуации вам потребуется другой обходной путь, подобный следующему: Сделайте это, когда файл создан или вы хотите начать обработку файла

long fileSize = 0;
currentFile = new FileInfo(path);

while (fileSize < currentFile.Length)//check size is stable or increased
{
  fileSize = currentFile.Length;//get current size
  System.Threading.Thread.Sleep(500);//wait a moment for processing copy
  currentFile.Refresh();//refresh length value
}

//Now file is ready for any process!
Решение Вопроса

с которой вы сталкиваетесь.

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

1st Method, copied directly from этот ответ:

private bool IsFileLocked(FileInfo file)
{
    FileStream stream = null;

    try
    {
        stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
    }
    catch (IOException)
    {
        //the file is unavailable because it is:
        //still being written to
        //or being processed by another thread
        //or does not exist (has already been processed)
        return true;
    }
    finally
    {
        if (stream != null)
            stream.Close();
    }

    //file is not locked
    return false;
}

2nd Method:

const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;
private bool IsFileLocked(string file)
{
    //check that problem is not in destination file
    if (File.Exists(file) == true)
    {
        FileStream stream = null;
        try
        {
            stream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
        }
        catch (Exception ex2)
        {
            //_log.WriteLog(ex2, "Error in checking whether file is locked " + file);
            int errorCode = Marshal.GetHRForException(ex2) & ((1 << 16) - 1);
            if ((ex2 is IOException) && (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION))
            {
                return true;
            }
        }
        finally
        {
            if (stream != null)
                stream.Close();
        }
    }
    return false;
}
 11 июн. 2012 г., 16:38
Хм, это прямо из:stackoverflow.com/a/937558/97000.
 17 мая 2016 г., 18:52
И вы забыли скопировать постоянные значения (ERROR_SHARING_VIOLATION = 32, ERROR_LOCK_VIOLATION = 33)

Ваш ответ на вопрос