接受您需要一种快速的方法来验证是否要花更多时间来调试代码,或者编写好的测试来证明您的代码是可以的,您想要的是一种快速的方法来证明没有其他进程正在使用您的文件. 所以,让我们假设:
- 您的文件在本地磁盘(不是网络共享)上,并且
- 您怀疑防病毒、Windows 索引或其他东西正在锁定文件而不是您的代码
- 因此,在编写测试之前,您需要一种快速的方法来限定输入/输出
您希望能够运行您的程序,并查看导致您遇到共享冲突时该文件发生了什么。
我会这样做:
1. 从 sysinternals 下载 ProcMon(10 秒)
Procmon 是一个出色的工具,您可以过滤到您希望在所有进程中按顺序看到的情况。链接到 sysinternals 上的 procmon,来自 Microsoft
2. 提取并运行 Procmon,添加过滤器和亮点(30 秒)
打开procmon,为“路径”添加一个过滤器“以”开头"
现在为“结果”“是”“共享违规”添加一个亮点
最后,运行程序直到出现异常,然后在路径列中右键单击存在共享冲突的文件,然后选择“包含'<此处的文件名>'”以删除所有其他结果。您现在可以查看导致异常的文件的所有活动...
如果你想熟悉 procmon,这里是我用来为你伪造这一切的代码。它有一个锁定文件的侧线程和一个尝试锁定文件的主线程。只需创建一个 C# 控制台应用程序即可。它看起来像这样:
因此,在不到 2 分钟的时间内,您就可以查看您的代码是否有问题或其他原因。前几天我用它来确定我的 Com 组件实际上正在使用备用文件流,因此在尝试使用网络驱动器时抛出了异常。没有多少单元测试可以帮助我。
这是强制共享冲突的测试代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.IO;
using System.Threading;
internal class Program
{
private static int lockPoint = 0;
private static void Main(string[] args)
{
const string testFile = @"H:\test\test.txt";
FileInfo testFileInfo = new FileInfo(testFile);
if (!testFileInfo.Directory.Exists)
{
testFileInfo.Directory.Create();
}
// Clear our example
if (testFileInfo.Exists)
{
testFileInfo.Delete();
}
// Create the test file
using (FileStream fs = File.Create(testFile))
using (StreamWriter sw = new StreamWriter(fs))
{
sw.WriteLine("test file content");
}
Task iLockTheFileFirst = new Task(() => {
using (FileStream fsThread = File.Open(testFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
Console.WriteLine("iLockTheFileFirst: I opened the file");
// Set lockPoint to 1 and let main try and open the file
Interlocked.Exchange(ref lockPoint, 1);
// Wait until the main thread sets lockPoint to 3
const int ifEqualTo3 = 3;
const int replaceWith4 = 4;
while (Interlocked.CompareExchange(ref lockPoint, replaceWith4, ifEqualTo3) != ifEqualTo3)
{
Console.WriteLine("iLockTheFileFirst: Waiting for main thread to let me finish");
Thread.Sleep(1000);
}
}
Console.WriteLine("iLockTheFileFirst: I have closed the file");
});
// Start the thread and lock the file
iLockTheFileFirst.Start();
// Now spin until the lockPoint becomes 1
const int ifEqualTo1 = 1;
const int replaceWith2 = 2;
// If lockPoint is equal to 1 (i.e. the main thread wants us to finish), then move it to 2
while (Interlocked.CompareExchange(ref lockPoint, replaceWith2, ifEqualTo1) != ifEqualTo1)
{
Console.WriteLine("Main thread: waiting for iLockTheFileFirst to open the file");
Thread.Sleep(1000);
}
try
{
Console.WriteLine("Main thread: now I'll try opening the file");
using (FileStream fsMain = File.Open(testFile, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
Console.WriteLine("Main thread: I opened the file, which shouldn't be possible");
}
}
catch (IOException ioex)
{
Console.WriteLine("Main thread: IOException: " + ioex.Message);
}
catch (Exception ex)
{
Console.WriteLine("Main thread: some other exception: " + ex.Message);
}
// Set lockPoint to 3 and let other thread finish
Interlocked.Exchange(ref lockPoint, 3);
// Wait for other thread to finish
const int ifEqualTo4 = 4;
const int replaceWith5 = 5;
while (Interlocked.CompareExchange(ref lockPoint, replaceWith5, ifEqualTo4) != ifEqualTo4)
{
Thread.Sleep(10);
}
Console.WriteLine("Main thread: Press enter to finish");
Console.ReadLine();
}
}
这就是所有的人!