首页 / C# / c#-并发File.Move同一文件
c#-并发File.Move同一文件
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了c#-并发File.Move同一文件,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4126字,纯文字阅读大概需要6分钟。
内容图文
![c#-并发File.Move同一文件](/upload/InfoBanner/zyjiaocheng/681/b2d2059f735a4fbdaaa5fd5c6241e1bd.jpg)
明确指出File.Move是原子操作:Atomicity of File.Move.
但是以下代码段可导致多次移动同一文件的可见性.
有人知道这段代码有什么问题吗?
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
namespace FileMoveTest
{
class Program
{
static void Main(string[] args)
{
string path = "test/" + Guid.NewGuid().ToString();
CreateFile(path, new string('a', 10 * 1024 * 1024));
var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
var task = Task.Factory.StartNew(() =>
{
try
{
string newPath = path + "." + Guid.NewGuid();
File.Move(path, newPath);
// this line does NOT solve the issue
if (File.Exists(newPath))
Console.WriteLine(string.Format("Moved {0} -> {1}", path, newPath));
}
catch (Exception e)
{
Console.WriteLine(string.Format(" {0}: {1}", e.GetType(), e.Message));
}
});
tasks.Add(task);
}
Task.WaitAll(tasks.ToArray());
}
static void CreateFile(string path, string content)
{
string dir = Path.GetDirectoryName(path);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
using (FileStream f = new FileStream(path, FileMode.OpenOrCreate))
{
using (StreamWriter w = new StreamWriter(f))
{
w.Write(content);
}
}
}
}
}
矛盾的输出如下.似乎该文件已多次移动到不同的位置.在磁盘上仅存在其中之一.有什么想法吗?
Moved test/eb85560d-8c13-41c1-926a-6871be030742 -> test/eb85560d-8c13-41c1-926a-6871be030742.0018d317-ed7c-4732-92ac-3bb974d29017 Moved test/eb85560d-8c13-41c1-926a-6871be030742 -> test/eb85560d-8c13-41c1-926a-6871be030742.3965dc15-7ef9-4f36-bdb7-94a5939b17db Moved test/eb85560d-8c13-41c1-926a-6871be030742 -> test/eb85560d-8c13-41c1-926a-6871be030742.fb66306a-5a13-4f26-ade2-acff3fb896be Moved test/eb85560d-8c13-41c1-926a-6871be030742 -> test/eb85560d-8c13-41c1-926a-6871be030742.c6de8827-aa46-48c1-b036-ad4bf79eb8a9 System.IO.FileNotFoundException: Could not find file 'C:\file-move-test\test\eb85560d-8c13-41c1-926a-6871be030742'. System.IO.FileNotFoundException: Could not find file 'C:\file-move-test\test\eb85560d-8c13-41c1-926a-6871be030742'. System.IO.FileNotFoundException: Could not find file 'C:\file-move-test\test\eb85560d-8c13-41c1-926a-6871be030742'. System.IO.FileNotFoundException: Could not find file 'C:\file-move-test\test\eb85560d-8c13-41c1-926a-6871be030742'. System.IO.FileNotFoundException: Could not find file 'C:\file-move-test\test\eb85560d-8c13-41c1-926a-6871be030742'. System.IO.FileNotFoundException: Could not find file 'C:\file-move-test\test\eb85560d-8c13-41c1-926a-6871be030742'.
结果文件在这里:
eb85560d-8c13-41c1-926a-6871be030742.fb66306a-5a13-4f26-ade2-acff3fb896be
更新.我可以确认检查File.Exists也不能解决问题-它可以报告单个文件确实已移至多个不同的位置.
解.我最终得到的解决方案如下:在对源文件进行操作之前,请创建一个特殊的“锁定”文件,如果成功,则可以确保只有该线程才可以对该文件进行独占访问,并且我们可以安全地执行任何所需的操作.以下是用于创建“锁定”文件的正确参数集.
File.Open(lockPath, FileMode.CreateNew, FileAccess.Write);
解决方法:
Does anyone know what is wrong with this code?
我想这取决于您所说的“错误”.
您所看到的行为并不是恕我直言,至少在使用NTFS时(其他文件系统可能会或可能不会有类似的行为).
底层OS API(MoveFile()和MoveFileEx()函数)的文档不是特定的,但总的来说API是线程安全的,因为它们保证文件系统不会被并发操作破坏(当然,您自己的数据可能会被破坏).已损坏,但将以文件系统一致的方式完成).
最有可能发生的是,随着移动文件操作的进行,它首先通过从给定目录链接获取实际的文件句柄来实现(在NTFS中,您看到的所有“文件名”实际上都是与基础文件对象).获得该文件句柄后,API随后为基础文件对象创建一个新文件名(即,作为硬链接),然后删除先前的硬链接.
当然,随着此过程的进行,在线程获得底层文件句柄之间但在删除原始硬链接之前的这段时间内,会有一个窗口.这允许其他所有并发移动操作(但不是全部)看起来都成功.即最终原始的硬链接不存在,进一步尝试移动它也不会成功.
无疑,以上内容过于简单.文件系统行为可能很复杂.特别是,您陈述的观察结果是,在全部说完之后,只结束了文件的单个实例.这表明API确实也以某种方式协调了各种操作,从而可能只有一个新创建的硬链接得以幸存,这可能是由于API实际上只是在检索文件对象句柄之后重命名了相关的硬链接,而不是创建一个新的,并删除旧的(实现细节).
归根结底,该代码的“错误”在于它有意尝试对单个文件执行并发操作.虽然文件系统本身将确保其保持一致性,但是由您自己的代码来确保这些操作得到协调以使结果可预测和可靠.
内容总结
以上是互联网集市为您收集整理的c#-并发File.Move同一文件全部内容,希望文章能够帮你解决c#-并发File.Move同一文件所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。