C# 写入文本文件-I/O错误

C# 写入文本文件-I/O错误,c#,.net,winforms,visual-studio,system.io.file,C#,.net,Winforms,Visual Studio,System.io.file,我收到以下运行时错误:“写入文件时出现I/O错误:”进程无法访问文件bin\Debug/test.txt,因为它正被另一个进程使用 我已经在所有正在写入的情况下关闭了文件,但使用File.ReadAllText(path)的情况除外,因为我的理解是filestream是自动关闭的。如何更正此错误 以下是相关代码: StreamReader sr = null; sr = new StreamReader(new FileStream(path, FileMode.Open, FileAcce

我收到以下运行时错误:“写入文件时出现I/O错误:”进程无法访问文件bin\Debug/test.txt,因为它正被另一个进程使用

我已经在所有正在写入的情况下关闭了文件,但使用File.ReadAllText(path)的情况除外,因为我的理解是filestream是自动关闭的。如何更正此错误

以下是相关代码:

 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();
       }           
   }
StreamWriter sw=null;
尝试
{
//打开同一个文件进行写入
sw=newstreamwriter(newfilestream(path,FileMode.Create,FileAccess.Write));
对于(int i=0;i
在第二个代码块中,怀疑您的代码未能调用
sw.Dispose()
,原因如下:

来自.NET源代码

public override void Close() {
     Dispose(true);
     GC.SuppressFinalize(this);
}
因此,当您调用
.Close()
时,框架将调用
Dispose(true)
。因此,当您显式地编写
sw.Dispose()
时,您正试图处理一个已被处理的
StreamWriter


删除
sw.Dispose()

在第二个代码块中,怀疑您的代码未能调用
sw.Dispose()
,原因如下:

来自.NET源代码

public override void Close() {
     Dispose(true);
     GC.SuppressFinalize(this);
}
因此,当您调用
.Close()
时,框架将调用
Dispose(true)
。因此,当您显式地编写
sw.Dispose()
时,您正试图处理一个已被处理的
StreamWriter

删除
sw.Dispose()

 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. 
    }
}
它更加健壮,特别是当异常发生时,因为无论发生什么情况,它都将被关闭

在本文中阅读更多关于使用(…)
的信息:


编辑:FileStream和StreamReader的堆叠使用您的前几行:

 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. 
    }
}
它更加健壮,特别是当异常发生时,因为无论发生什么情况,它都将被关闭

在本文中阅读更多关于使用(…)的信息:



编辑:FileStream和StreamReader的堆叠使用Windows不允许两个进程共享文件系统流,因此您无法解决此问题,但您可以在使用文件时等待,然后访问它

我建议您避免使用循环来提出解决方案(
for
while
或递归调用),因为它们可能会导致内存泄漏。相反,我建议您使用旋转循环(这是一个等待下一个时钟周期到达下一个迭代的循环)

这种循环已经在大多数语言中实现,例如C#

首先,导入以下内容:

using System.Threading;
然后,调用
SpinWait.spinUtil
Func
委托作为参数传递:该委托将被调用,直到它返回
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)
    {
    }
}

Windows不允许两个进程共享一个文件系统流,因此您无法解决该问题,但您可以在使用该文件时等待,然后访问它

我建议您避免使用循环来提出解决方案(
for
while
或递归调用),因为它们可能会导致内存泄漏。相反,我建议您使用旋转循环(这是一个等待下一个时钟周期到达下一个迭代的循环)

这种循环已经在大多数语言中实现,例如C#

首先,导入以下内容:

using System.Threading;
然后,调用
SpinWait.spinUtil
Func
委托作为参数传递:该委托将被调用,直到它返回
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)
    {
    }
}

错误是从写代码还是从读代码中抛出的?我假设这两个代码块位于两个不同的方法中。请说明调用这些方法的方式和顺序,以及调试器在哪一行抛出错误?(假设您使用调试器逐行逐行遍历代码)@333写入,在第二个代码块中,它表示“写入文件时出现I/O错误”“注意,您还可能对已处理的对象调用
Close
,并且正在处理它们两次。您在try块内对读写器调用
Close
Dispose
,但没有将它们设置为
null
,然后在finally中调用
Close
Dispose
,如果对象不是
null
@Sohel-我认为没有必要发布整个代码。实际上,解决这类问题的最佳方法之一是开始删除代码,或者尝试创建一个小程序来重现问题(请参阅)。在尝试创建MCVE时,我们实际上发现了问题所在。错误是从