写入文本文件 - I/O 错误
Writing to a Text File - I/O Error
我收到以下 运行 时间错误:"I/O error while writing the file: "进程无法访问文件 bin\Debug/test.txt,因为它正被另一个进程使用。"
我已经关闭了所有正在写入的文件,但使用 File.ReadAllText(path) 的情况除外,因为我的理解是文件流会自动关闭。我该如何纠正这个错误?
相关代码如下:
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();
}
}
在您的第二个代码块中,怀疑您的代码无法调用 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 个共享读取访问权限 - 您只是 closing/disposing 其中之一。
切换到
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( ... )
的内容 post:What are the uses of "using" in C#
编辑:FileStream 和 StreamReader 的堆叠使用
Windows 不允许两个进程共享一个文件系统流,所以你不能解决这个问题,但是你可以等待文件被使用,然后访问它。
我建议你避免使用loopE来解决(for
、while
或递归调用),因为它们可能会导致内存泄漏。相反,我建议您使用旋转循环(这是一个等待下一个时钟周期到达下一个迭代的循环)。
这种循环已经在大多数语言中实现了,比如C#。
首先,导入这个:
using System.Threading;
然后,调用 SpinWait.SpinUntil
传递一个 Func<bool>
委托作为参数:该委托将被调用,直到它 returns 一个 true
条件。
SpinWait.SpinUntil(delegate
{
try
{
File.Open("yourPath", FileMode.Open, FileAccess.Read, FileShare.None);
}
catch
{
return false;
}
return true;
});
此时,您正在等待,直到您可以打开该文件的流,然后再打开它!
显然,您也可以创建一个有用的 class:
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
(除非您使用文件句柄,我的 class 尚不支持此功能):
StreamReader sr = new StreamReader(new HardFileStream(path, FileMode.Open, FileAccess.Read));
我收到以下 运行 时间错误:"I/O error while writing the file: "进程无法访问文件 bin\Debug/test.txt,因为它正被另一个进程使用。"
我已经关闭了所有正在写入的文件,但使用 File.ReadAllText(path) 的情况除外,因为我的理解是文件流会自动关闭。我该如何纠正这个错误?
相关代码如下:
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();
}
}
在您的第二个代码块中,怀疑您的代码无法调用 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 个共享读取访问权限 - 您只是 closing/disposing 其中之一。
切换到
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( ... )
的内容 post:What are the uses of "using" in C#
编辑:FileStream 和 StreamReader 的堆叠使用
Windows 不允许两个进程共享一个文件系统流,所以你不能解决这个问题,但是你可以等待文件被使用,然后访问它。
我建议你避免使用loopE来解决(for
、while
或递归调用),因为它们可能会导致内存泄漏。相反,我建议您使用旋转循环(这是一个等待下一个时钟周期到达下一个迭代的循环)。
这种循环已经在大多数语言中实现了,比如C#。
首先,导入这个:
using System.Threading;
然后,调用 SpinWait.SpinUntil
传递一个 Func<bool>
委托作为参数:该委托将被调用,直到它 returns 一个 true
条件。
SpinWait.SpinUntil(delegate
{
try
{
File.Open("yourPath", FileMode.Open, FileAccess.Read, FileShare.None);
}
catch
{
return false;
}
return true;
});
此时,您正在等待,直到您可以打开该文件的流,然后再打开它!
显然,您也可以创建一个有用的 class:
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
(除非您使用文件句柄,我的 class 尚不支持此功能):
StreamReader sr = new StreamReader(new HardFileStream(path, FileMode.Open, FileAccess.Read));