File.Delete 错误“该进程无法访问该文件,因为该文件正在被另一个进程使用”

发布于 2024-09-12 23:27:33 字数 412 浏览 4 评论 0原文

我编写了一个 DotUnit 测试套件,用于测试应用程序中的一些数据导入功能。它的工作原理是备份一些本地 Microsoft Access 数据库(我们将其称为“Test.mdb”)到“Test.mdb.bak”,执行一些数据导入(以及后续的断言检查),然后从备份中恢复原始数据。

如果备份不存在,SetUp() 函数会创建一个。

TearDown() 函数尝试删除“Test.mdb”,然后将“Test.mdb.bak”复制到“Test.mdb”。

间歇性运行测试失败,并出现此错误“该进程无法访问该文件,因为该文件正在被另一个进程使用”。

我查看了 MSDN 关于 File.Delete 和 IO 权限的内容,但找不到我想要的内容。有谁知道是否有 .NET 功能可以让我在尝试删除文件之前完全锁定该文件?或者找到删除时哪个进程正在访问它?

I have written a DotUnit test suite for testing some data import functionality in my application. It works by making a backup of some local Microsoft Access Database, let's call it 'Test.mdb', to 'Test.mdb.bak', performing some data import (and subsequent Assert checks) and then restoring the original from the backup.

The SetUp() function creates a backup if one doesn't exist.

The TearDown() function attempts to delete 'Test.mdb' and then copy 'Test.mdb.bak' to 'Test.mdb'.

Intermittently running the tests fail with this error "The process cannot access the file because it is being used by another process".

I've had a look the MSDN on File.Delete and IO permissions but couldn't find what I was after. Does anyone know if there is a .NET feature that will allow me to completely lock the file before attempting to delete it? Or find which process is accessing it at the time of deletion?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南烟 2024-09-19 23:27:33

我在使用 SQLite 数据库对实体框架代码进行单元测试时遇到了类似的问题,其中每个测试都需要使用数据库的新实例,因此我的 [TestCleanup] 方法正在数据库上执行 File.Delete,但得到了相同的结果“被另一个进程使用”错误。

在调用 File.Delete 之前,我必须添加以下内容来解决我的问题。

GC.Collect();

GC.WaitForPendingFinalizers();

[TestInitialize]
public void MyTestInitialize()
{
    // Copies the embedded resource 'MyDatabase.db' to the Testing Directory
    CommonTestFixture.UnpackFile("MyDatabase.db", this.GetType(), this.TestContext.TestDeploymentDir);
}

[TestCleanup]
public void MyTestCleanup()
{
    // Adding the following two lines of code fixed the issue
    GC.Collect();
    GC.WaitForPendingFinalizers();

    // Removes 'MyDatabase.db' from the testing directory.
    File.Delete(Path.Combine(this.TestContext.TestDeploymentDir, "MyDatabase.db"));
}

[TestMethod]
public void GetVenueTest()
{
    // CreateTestEntities() is a helper that initializes my entity framework DbContext
    // with the correct connection string for the testing database.
    using (var entityFrameworkContext = CreateTestEntities())
    {
        // Do whatever testing you want here:
        bool result = entityFrameworkContext.TestSomething()
        Assert.IsTrue(result);
    }
}

I had a similar issue while unit testing Entity Framework code using a SQLite database where each test needed to use a fresh instance of a database, so my the [TestCleanup] method was doing a File.Delete on the database, but was getting the same "used by another process" error.

Before I called, File.Delete, I had to add the following to fix my issue.

GC.Collect();

GC.WaitForPendingFinalizers();

[TestInitialize]
public void MyTestInitialize()
{
    // Copies the embedded resource 'MyDatabase.db' to the Testing Directory
    CommonTestFixture.UnpackFile("MyDatabase.db", this.GetType(), this.TestContext.TestDeploymentDir);
}

[TestCleanup]
public void MyTestCleanup()
{
    // Adding the following two lines of code fixed the issue
    GC.Collect();
    GC.WaitForPendingFinalizers();

    // Removes 'MyDatabase.db' from the testing directory.
    File.Delete(Path.Combine(this.TestContext.TestDeploymentDir, "MyDatabase.db"));
}

[TestMethod]
public void GetVenueTest()
{
    // CreateTestEntities() is a helper that initializes my entity framework DbContext
    // with the correct connection string for the testing database.
    using (var entityFrameworkContext = CreateTestEntities())
    {
        // Do whatever testing you want here:
        bool result = entityFrameworkContext.TestSomething()
        Assert.IsTrue(result);
    }
}
野稚 2024-09-19 23:27:33

您可能会重新考虑您的测试方法。相反:

  1. 创建文件的临时副本
  2. 执行在临时文件上测试的操作
  3. 释放临时文件的所有句柄(关闭所有连接)
  4. 删除临时文件

使用此模式,将访问该文件的唯一进程将是运行单元测试的线程。

使用函数:System.IO.Path.GetTempFileName();

http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx

编辑: 这是一种方法对其进行编码:

var tempFile = System.IO.Path.GetTempFileName();
System.IO.File.Copy(@"C:\Test.mdb", tempFile, true);
// 2. Test tempFile
// 3. Release handles to tempFile, use a using statement around any 
//    streams or System.IO API's that are using the file in any way.
System.IO.File.Delete(tempFile);

You might reconsider your testing approach. Instead:

  1. Create a temporary copy of the file
  2. Perform the actions that are being tested on the temp file
  3. Release all handles (close all connections) to the temp file
  4. Delete the temp file

Using this pattern, the only process that will be accessing the file will be the thread running the unit test.

Use the function: System.IO.Path.GetTempFileName();

http://msdn.microsoft.com/en-us/library/system.io.path.gettempfilename.aspx

EDIT: Here is one way to code it:

var tempFile = System.IO.Path.GetTempFileName();
System.IO.File.Copy(@"C:\Test.mdb", tempFile, true);
// 2. Test tempFile
// 3. Release handles to tempFile, use a using statement around any 
//    streams or System.IO API's that are using the file in any way.
System.IO.File.Delete(tempFile);
妞丶爷亲个 2024-09-19 23:27:33

这两行解决了这个问题。

GC.Collect();
GC.WaitForPendingFinalizers();

我已经在我的代码中对此进行了测试,效果很好。

---吉腾德拉

These two lines solve the issue.

GC.Collect();
GC.WaitForPendingFinalizers();

I have tested this in my code and it worked well.

--- Jeetendra

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文