C# 等待文件完全写入
在一个目录中创建文件(C# 等待文件完全写入,c#,file,io,filesystems,copy,C#,File,Io,Filesystems,Copy,在一个目录中创建文件(FileSystemWatcher\u created)时,我会将其复制到另一个目录。但是,当我创建一个大(>10MB)文件时,它无法复制该文件,因为它已经开始复制,而此时文件尚未完成创建… 这会导致无法复制该文件,因为另一个进程正在使用该文件来引发该文件。;( 有什么帮助吗 class Program { static void Main(string[] args) { string path = @"D:\levan\FolderLis
FileSystemWatcher\u created
)时,我会将其复制到另一个目录。但是,当我创建一个大(>10MB)文件时,它无法复制该文件,因为它已经开始复制,而此时文件尚未完成创建…这会导致无法复制该文件,因为另一个进程正在使用该文件来引发该文件。;(
有什么帮助吗
class Program
{
static void Main(string[] args)
{
string path = @"D:\levan\FolderListenerTest\ListenedFolder";
FileSystemWatcher listener;
listener = new FileSystemWatcher(path);
listener.Created += new FileSystemEventHandler(listener_Created);
listener.EnableRaisingEvents = true;
while (Console.ReadLine() != "exit") ;
}
public static void listener_Created(object sender, FileSystemEventArgs e)
{
Console.WriteLine
(
"File Created:\n"
+ "ChangeType: " + e.ChangeType
+ "\nName: " + e.Name
+ "\nFullPath: " + e.FullPath
);
File.Copy(e.FullPath, @"D:\levan\FolderListenerTest\CopiedFilesFolder\" + e.Name);
Console.Read();
}
}
你真的很幸运-编写文件的程序会锁定它,因此你无法打开它。如果它没有锁定它,你可能会复制一个部分文件,而不知道有问题 当您无法访问某个文件时,您可以假定该文件仍在使用中(更好的做法是尝试以独占模式打开它,并查看是否有其他人正在打开它,而不是从file.Copy的失败中猜测)。如果该文件已锁定,您将不得不在其他时间复制它。如果未锁定,您可以复制它(这里有轻微的比赛条件的可能性)
“其他时间”是什么时候?我不记得FileSystemWatcher何时会为每个文件发送多个事件-请检查,您只需忽略该事件并等待另一个事件就足够了。如果不是,您可以设置一个时间,并在5秒钟内重新检查该文件。来自
FileSystemWatcher
的文档:
一旦创建文件,就会引发OnCreated
事件。如果
正在复制或传输到监视的目录中
OnCreated
事件将立即引发,然后引发一个或多个事件
OnChanged
事件
因此,如果复制失败,(捕获异常),将其添加到仍然需要移动的文件列表中,并在OnChanged
事件期间尝试复制。最终,它应该可以工作
类似(不完整;捕获特定异常、初始化变量等):
}对于您面临的问题,只有解决办法 在开始复制过程之前,请检查文件id是否在处理中。您可以调用以下函数,直到获得False值 第一种方法,直接复制自:
private bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;
private bool IsFileLocked(string file)
{
//check that problem is not in destination file
if (File.Exists(file) == true)
{
FileStream stream = null;
try
{
stream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (Exception ex2)
{
//_log.WriteLog(ex2, "Error in checking whether file is locked " + file);
int errorCode = Marshal.GetHRForException(ex2) & ((1 << 16) - 1);
if ((ex2 is IOException) && (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION))
{
return true;
}
}
finally
{
if (stream != null)
stream.Close();
}
}
return false;
}
第二种方法:
private bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
const int ERROR_SHARING_VIOLATION = 32;
const int ERROR_LOCK_VIOLATION = 33;
private bool IsFileLocked(string file)
{
//check that problem is not in destination file
if (File.Exists(file) == true)
{
FileStream stream = null;
try
{
stream = File.Open(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (Exception ex2)
{
//_log.WriteLog(ex2, "Error in checking whether file is locked " + file);
int errorCode = Marshal.GetHRForException(ex2) & ((1 << 16) - 1);
if ((ex2 is IOException) && (errorCode == ERROR_SHARING_VIOLATION || errorCode == ERROR_LOCK_VIOLATION))
{
return true;
}
}
finally
{
if (stream != null)
stream.Close();
}
}
return false;
}
const int ERROR\u SHARING\u违规=32;
const int ERROR\u LOCK\u违例=33;
私有bool IsFileLocked(字符串文件)
{
//检查目标文件中是否不存在问题
if(File.Exists(File)==true)
{
FileStream=null;
尝试
{
stream=File.Open(File,FileMode.Open,FileAccess.ReadWrite,FileShare.None);
}
捕获(异常ex2)
{
//_log.WriteLog(ex2,“检查文件是否锁定时出错”+文件);
int errorCode=Marshal.GetHRForException(ex2)和((1您已经自己给出了答案;您必须等待文件创建完成。一种方法是检查文件是否仍在使用中。这里可以找到一个示例:
请注意,您必须修改此代码才能使其在您的情况下工作。您可能需要类似(伪代码)的代码:
显然,您应该在
期间保护自己免受无限的攻击,以防所有者应用程序从未释放锁。此外,您可能需要从您可以订阅的FileSystemWatcher
中查看其他事件。可能有一个事件可以用来规避整个问题。您可以使用允许使用代码检查文件是否可以以独占访问权限打开(即,它未被其他应用程序打开)。如果文件未关闭,您可以等待几分钟,然后再次检查,直到文件关闭,并且您可以安全地复制它
您仍然应该检查File.Copy是否失败,因为在您检查文件和复制文件之间,其他应用程序可能会打开该文件
public static bool IsFileClosed(string filename)
{
try
{
using (var inputStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.None))
{
return true;
}
}
catch (IOException)
{
return false;
}
}
这是一个旧的线程,但我会为其他人添加一些信息
我在一个编写PDF文件的程序中遇到了类似的问题,有时它们需要30秒来渲染..这与我的watcher_FileCreated类在复制文件之前等待的时间相同
文件没有被锁定
在本例中,我检查了PDF的大小,然后在比较新大小之前等待了2秒,如果它们不相等,线程将休眠30秒,然后重试。我想在这里添加一个答案,因为这对我很有效。我使用了延时,而循环,我能想到的一切
我打开了输出文件夹的Windows资源管理器窗口,关闭了它,一切都很顺利
我希望这对其他人有所帮助。当文件以二进制(逐字节)写入时,创建FileStream和以上解决方案不起作用,因为文件已准备就绪,并且每个字节都已写入,因此在这种情况下,您需要类似以下的其他解决方法:
在创建文件或要开始处理文件时执行此操作
long fileSize = 0;
currentFile = new FileInfo(path);
while (fileSize < currentFile.Length)//check size is stable or increased
{
fileSize = currentFile.Length;//get current size
System.Threading.Thread.Sleep(500);//wait a moment for processing copy
currentFile.Refresh();//refresh length value
}
//Now file is ready for any process!
long fileSize=0;
currentFile=新文件信息(路径);
while(fileSize
因此,在快速浏览了其中一些问题和其他类似问题后,我今天下午进行了一次愉快的追逐,试图用两个单独的程序来解决一个问题,它们使用一个文件作为同步(以及文件保存)方法。有点不寻常的情况,但它明确地向我强调了“检查文件是否已锁定,如果未锁定则打开”方法的问题
问题是:在您检查文件和实际打开文件之间,文件可能会被锁定。很难找到零星的文件,因为如果您不查找它,它会被另一个进程使用
基本决议是:
/// <param name="timeout">how long to keep trying in milliseconds</param>
static void safeCopy(string src, string dst, int timeout)
{
while (timeout > 0)
{
try
{
File.Copy(src, dst);
//don't forget to either return from the function or break out fo the while loop
break;
}
catch (IOException)
{
//you could do the sleep in here, but its probably a good idea to exit the error handler as soon as possible
}
Thread.Sleep(100);
//if its a very long wait this will acumulate very small errors.
//For most things it's probably fine, but if you need precision over a long time span, consider
// using some sort of timer or DateTime.Now as a better alternative
timeout -= 100;
}
}
public class FileEx
{
public static async void CopyWaitAsync(string src, string dst, int timeout, Action doWhenDone)
{
while (timeout > 0)
{
try
{
File.Copy(src, dst);
doWhenDone();
break;
}
catch (IOException) { }
await Task.Delay(100);
timeout -= 100;
}
}
public static async Task<string> ReadAllTextWaitAsync(string filePath, int timeout)
{
while (timeout > 0)
{
try {
return File.ReadAllText(filePath);
}
catch (IOException) { }
await Task.Delay(100);
timeout -= 100;
}
return "";
}
public static async void WriteAllTextWaitAsync(string filePath, string contents, int timeout)
{
while (timeout > 0)
{
try
{
File.WriteAllText(filePath, contents);
return;
}
catch (IOException) { }
await Task.Delay(100);
timeout -= 100;
}
}
}
public static void Main()
{
test_FileEx();
Console.WriteLine("Me First!");
}
public static async void test_FileEx()
{
await Task.Delay(1);
//you can do this, but it gives a compiler warning because it can potentially return immediately without finishing the copy
//As a side note, if the file is not locked this will not return until the copy operation completes. Async functions run synchronously
//until the first 'await'. See the documentation for async: https://msdn.microsoft.com/en-us/library/hh156513.aspx
CopyWaitAsync("file1.txt", "file1.bat", 1000);
//this is the normal way of using this kind of async function. Execution of the following lines will always occur AFTER the copy finishes
await CopyWaitAsync("file1.txt", "file1.readme", 1000);
Console.WriteLine("file1.txt copied to file1.readme");
//The following line doesn't cause a compiler error, but it doesn't make any sense either.
ReadAllTextWaitAsync("file1.readme", 1000);
//To get the return value of the function, you have to use this function with the await keyword
string text = await ReadAllTextWaitAsync("file1.readme", 1000);
Console.WriteLine("file1.readme says: " + text);
}
//Output:
//Me First!
//file1.txt copied to file1.readme
//file1.readme says: Text to be duplicated!