Запись в текстовый файл - ошибка ввода / вывода - PullRequest
0 голосов
/ 27 апреля 2018

Я получаю следующую ошибку во время выполнения: «Ошибка ввода-вывода при записи файла:« Процесс не может получить доступ к файлу bin \ Debug / test.txt, поскольку он используется другим процессом. »

Я закрыл файлы во всех случаях, когда они пишутся, за исключением случая, когда используется File.ReadAllText (путь), насколько я понимаю, что файловый поток автоматически закрывается. Как мне исправить эту ошибку?

Вот соответствующий код:

 StreamReader sr = null;
 sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));
 try
 {
     // Open the file for reading; assumes file exists
     sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));

     while (!sr.EndOfStream)
     {
         line = sr.ReadLine();
         fields = line.Split(',');
         aniNameCol1[count] = fields[0];
         aniNameCol2[count] = fields[1];
         aniNameCol3[count] = fields[2];
         aniNameCol4[count] = fields[3];

         count++;
     }
     sr.Close();
     sr.Dispose();

}
catch (FileNotFoundException)
{
    MessageBox.Show("File Not Found" + path);
}
catch (Exception ex)
{
    MessageBox.Show("Error while reading the file: " + ex.GetType().ToString() + ": " + ex.Message);
}
finally
{
    if (sr != null)
    {
        sr.Close();
        sr.Dispose();
    }                                          
}

try
{
     string input = File.ReadAllText(path);
     int i = 0;
     int j = 0;

     foreach (var row in input.Split('\n'))                  
     {
         j = 0;
         foreach (var col in row.Trim().Split(','))
         {
             twoDArray[i, j] = col.Trim().ToString();
             j++;
         }
         i++;
     }
 }
 catch (FileNotFoundException)
 {
     MessageBox.Show("File Not Found" + path);
 }
 catch (Exception ex)
 {
     MessageBox.Show("Error while reading the file: " + ex.GetType().ToString() + ": " + ex.Message);
 }

В другом методе текст записывается в файл:

 StreamWriter sw = null;
 try
 {
     // open the same file for writing            
     sw = new StreamWriter(new FileStream(path, FileMode.Create, FileAccess.Write));

     for(int i = 0; i < rowMax; i++)
     {
         for(int j = 0; j < colMax; j++)
         {
             sw.WriteLine(twoDArray[i, j].ToString() + ", ");
         }
     }
     sw.Close();
     sw.Dispose();
  }
  catch (IOException ex)
  {
    MessageBox.Show("I/O error while writing the file: " + ex.Message);
  }
  catch (Exception ex)
  {
    MessageBox.Show("Unanticipated error occurred while writing: " + ex.GetType() + "; " + ex.Message);
   }   
   finally
   {
       if (sw != null)
       {
          sw.Close();
          sw.Dispose();
       }           
   }

Ответы [ 3 ]

0 голосов
/ 28 апреля 2018

Ваши первые несколько строк:

 StreamReader sr = null;
 // opened the first time
 sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));
 try
 {
     // opened it a second time  
     sr = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read));

Ваша операционная система имеет 2 общих доступа для чтения файла - вы закрываете / удаляете только один из них.

Переключиться на

using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
    using (var sr = new StreamReader(fs))
    {
        // do your stuff here, no need to close or flush - it is autoclosed
        // when leaving the block.  Do the same for writing. 
    }
}

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

Подробнее о using( ... ) в этом посте: Какая польза от "использования" в C #


Редактировать: сложенные значения для FileStream и StreamReader

0 голосов
/ 28 апреля 2018

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

Я предлагаю вам избегать использования в loopE решения (for, while или рекурсивного вызова), поскольку они могут вызвать утечки памяти. Вместо этого я предлагаю вам использовать вращающийся цикл (это цикл, который ожидает следующего тактового цикла, чтобы достичь следующей итерации).

Этот вид цикла уже реализован в большинстве языков, таких как C #.

Сначала импортируйте это:

using System.Threading;

Затем вызовите SpinWait.SpinUntil, передав в качестве параметра делегат Func<bool>: этот делегат будет вызываться до тех пор, пока он не вернет условие true.

SpinWait.SpinUntil(delegate
{
    try
    {
        File.Open("yourPath", FileMode.Open, FileAccess.Read, FileShare.None);
    }
    catch
    {
        return false;
    }
    return true;
});

На данный момент вы ждете, пока не сможете открыть поток для файла, а затем откройте его!

Очевидно, вы также можете создать полезный класс:

using System.Diagnostics;
using System.Threading;

public class HardFileStream : FileStream
{

    [DebuggerHidden, DebuggerStepperBoundary]
    private static T Preconstructor<T>(T value, string path)
    {
        SpinWait.SpinUntil(delegate
        {
            try
            {
                using (File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                {
                }
            }
            catch
            {
                return false;
            }
            return true;
        });
        Thread.MemoryBarrier();
        return value;
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode)
        : base(Preconstructor(path, path), mode)
    {
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode, FileAccess access)
        : base(Preconstructor(path, path), mode, access)
    {
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode, FileAccess access, FileShare share)
        : base(Preconstructor(path, path), mode, access, share)
    {
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize)
        : base(Preconstructor(path, path), mode, access, share, bufferSize)
    {
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, FileOptions options)
        : base(Preconstructor(path, path), mode, access, share, bufferSize, options)
    {
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync)
        : base(Preconstructor(path, path), mode, access, share, bufferSize, useAsync)
    {
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options)
        : base(Preconstructor(path, path), mode, rights, share, bufferSize, options)
    {
    }

    [DebuggerHidden, DebuggerStepperBoundary]
    public HardFileStream(string path, FileMode mode, FileSystemRights rights, FileShare share, int bufferSize, FileOptions options, FileSecurity fileSecurity)
        : base(Preconstructor(path, path), mode, rights, share, bufferSize, options, fileSecurity)
    {
    }
}

Затем вы можете использовать HardFileStream вместо FileStream (кроме случаев, когда вы используете файловые дескрипторы, функция, которая еще не поддерживается в моем классе):

StreamReader sr = new StreamReader(new HardFileStream(path, FileMode.Open, FileAccess.Read));
0 голосов
/ 28 апреля 2018

В вашем втором блоке кода подозревайте, что ваш код не может вызвать sw.Dispose(), и вот почему:

Из исходного кода .NET

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

Итак, когда вы звоните .Close(), фреймворк будет вызывать Dispose(true). Поэтому, когда вы явно пишете sw.Dispose(), вы пытаетесь избавиться от StreamWriter, который уже был удален.

Удалить sw.Dispose()

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