SSD 驱动器上奇怪的目录删除行为
目录 c:\test 有 50 个左右的文件,没有子目录。
If IO.Directory.Exists("C:\test") Then
IO.Directory.Delete("C:\test", True)
End If
IO.Directory.CreateDirectory("C:\test")
驱动器 C 是 Intel 的 X25-M80 SSD 驱动器,操作系统是 Windows 7 64 位,支持 TRIM,Visual Studio 是 2008,目标框架 3.5。当执行上述代码时,CreateDirectory 会中断代码执行,而不会出现(可见的)异常。经过一番头痛之后,我发现当代码执行到 CreateDirectory 时,删除尚未完成。如果我像这样修改我的代码:
If IO.Directory.Exists("C:\test") Then
IO.Directory.Delete("C:\test", True)
End If
Threading.Thread.Sleep(2000)
IO.Directory.CreateDirectory("C:\test")
那么一切都会按预期工作。
除了明显的 WTF 之外,我的问题是:
- 无论驱动器是什么,IO.Directory.Delete 不应该是一个阻塞函数调用吗
- ?由于启用了 TRIM 支持,SSD 在删除时“作弊”吗?
Directory c:\test has 50 or so files in it, no subdirectories.
If IO.Directory.Exists("C:\test") Then
IO.Directory.Delete("C:\test", True)
End If
IO.Directory.CreateDirectory("C:\test")
Drive C is Intel's X25-M80 SSD drive, OS is Windows 7 64 bit with TRIM support, Visual Studio is 2008 with target framework 3.5. When above code is executed, CreateDirectory breaks code execution without an (visible) exception. After much headache I found that Delete is not yet done by the time code execution gets to CreateDirectory. If I modify my code like this:
If IO.Directory.Exists("C:\test") Then
IO.Directory.Delete("C:\test", True)
End If
Threading.Thread.Sleep(2000)
IO.Directory.CreateDirectory("C:\test")
then everything works as expected.
My questions beside the obvious WTF here are:
- shouldn't IO.Directory.Delete be a blocking function call no matter what the drive is
- is SSD "cheating" on delete due to enabled TRIM support?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我以前遇到过这个问题,但这并不是 SSD 驱动器特有的。最好先移动然后删除:
另一种处理方法是循环直到完成:
I've had problems with this before, but this is not specific to SSD drives. You would be far better off doing a move then delete:
The other way to deal with it is to loop until complete:
使用反射器探索 System.IO.Directory 后,看起来 .Delete 只是 FindFirstFile、FindNextFile 和 RemoveDirectory Win API 调用的包装器。 .Net 运行时对这些 API 调用或 API 实现本身的调用没有任何线程或异步内容。
现在,假设它在某种程度上是 TRIM 问题,您可以通过打开提升的命令提示符并使用 fsutil 来禁用 TRIM:
要启用,请使用 0 作为参数运行相同的命令。
要查询,请使用 query 作为命令参数:
After exploring System.IO.Directory with reflector, it looks like .Delete is just a wrapper around the FindFirstFile, FindNextFile, and RemoveDirectory Win API calls. There's nothing threaded or asynchronous about the .Net runtime's invokation of those API calls, or the API implementation themselves.
Now, supposing its somehow a TRIM issue, you can disable TRIM by opening an elevated command prompt and using fsutil:
To enable, run the same command with 0 as parameter.
To query, use query as the command argument:
是的,这与 SSD 驱动器无关。我遇到了同样的问题,但仅限于客户端笔记本电脑。我正在使用.NET 3.5。就我而言,该目录只有一个文件。 CreateDirectory 似乎在删除完成之前首先在内部执行。
该代码在许多计算机上运行了三年,效果良好。客户换了一台新笔记本电脑,代码对他来说始终失败。我无法在具有相同配置的开发/测试机器上重现该场景。
Yes, it has nothing to do with SSD drive. I had same problem but only on a client laptop. I am using .NET 3.5. In my case, the directory had a single file. CreateDirectory seems to be executing first internally before Delete is finished.
This was a code that worked well for three years on many computers. Client changed to a new laptop and the code consistently fails for him. I can not reproduce the scenario on development/test machines with same configuration.
我也有同样的问题。我最终只删除了目录
@"C:\test"
的内容并将新文件复制到该目录。这是我的问题:使用 Directory.Delete() 和Directory.CreateDirectory() 覆盖文件夹
I had the same problem. I ended up deleting only the contents of the directory
@"C:\test"
and copying the new files to the directory. That was my problem:Using Directory.Delete() and Directory.CreateDirectory() to overwrite a folder
我怀疑您在 NTFS 中发现了一个竞争条件,该条件以前没有暴露过,因为不存在足够快的驱动器来命中它。我不认为 TRIM 与它有任何关系(尽管我保留犯错的权利!)
无论哪种方式,处理此问题的正确方法是将代码放入 Retry 循环中:
I suspect that you've found a race condition in NTFS that was previously not exposed since drives didn't exist that were fast enough to hit it. I don't think that TRIM has anything to do with it (though I reserve the right to be wrong!)
Either way, the proper way to handle this is to put the code in a Retry loop:
如果这确实是应用程序代码,请注意您实际上是在尝试删除名为“est”的目录!
将路径转义为“c:\test”或使用@运算符@“c:\test”。
If that's really the application code, note that you are really trying to delete the directory named "est"!
Escape your path to be "c:\test" or use the @ operator @"c:\test".