繁体   English   中英

C# - File.Move - 找不到文件

[英]C# - File.Move - Could not find file

File.Move 方法有一个奇怪的问题。 一般来说,我有一个服务,它监视远程共享上出现的新文件,一旦他们这样做,它就会通过“ren”cmd function 更改其扩展名并调用其他服务。 然后,此其他服务使用 File.Move 再次更改文件的扩展名。 问题是有时第二个服务失败并从 System.IO.File.InternalMove 返回错误“找不到文件...”,而文件已经存在。

起初我以为可能是网络连接的问题,但我感觉它经常是由网络问题引起的。

接下来我开始深入研究 .net 源代码,发现了一些有趣的东西:

        if (!InternalExists(fullSourceFileName))
             __Error.WinIOError(Win32Native.ERROR_FILE_NOT_FOUND, fullSourceFileName);
        
        if (!Win32Native.MoveFile(fullSourceFileName, fullDestFileName))
        {
            __Error.WinIOError();
        }

这是 File.InternalMove 方法的一部分,据我了解,该方法返回“找不到文件...”错误。 简而言之,InternalExists 方法是通过检查 Marshal.GetLastWin32Error() 错误和稍后验证文件上的属性来检查文件是否存在。

另外奇怪的是,这种方法似乎使用了某种“hack”(不知道它是否与我的问题有关,但令人担忧):

   // For floppy drives, normally the OS will pop up a dialog saying
            // there is no disk in drive A:, please insert one.  We don't want that.
            // SetErrorMode will let us disable this, but we should set the error
            // mode back, since this may have wide-ranging effects.
            bool success = false;
            int oldMode = Win32Native.SetErrorMode(Win32Native.SEM_FAILCRITICALERRORS);
            try {
                success = Win32Native.GetFileAttributesEx(path, GetFileExInfoStandard, ref data);
            }
            finally {
                Win32Native.SetErrorMode(oldMode);
            }

现在有趣的部分:) Class FileInfo 还允许通过 MoveTo() 方法重命名文件。 在这种方法中,“移动”部分如下:

 if (!Win32Native.MoveFile(FullPath, fullDestFileName))
            __Error.WinIOError();

它与文件 class 中的相同,但它缺少“InternalExists”验证,所以乍一看它应该可以解决我的问题,但我有点担心这个缺失的检查。

有谁知道为什么它是这样实现的,如果我可以使用 FileInfo.MoveTo 方法? 另外,如果您对问题的原因有任何想法,请分享。 目前我正在质疑,当第一个服务调用“ren”cmd 程序时,新文件还没有完全重命名,这导致 File.Move 方法失败,但我还需要验证它。

我猜这个错误实际上是一个权限问题,或者可能是一个锁定的文件,并且InternalExists返回的错误实际上不是ERROR_FILE_NOT_FOUND ,因为没有对其进行检查。

因此,没有抛出正确的错误是一个错误。

无论如何,为什么需要存在 Exists 检查尚不清楚:如果不存在,则在调用MoveFile时无论如何都会出错。

我建议你在 GitHub repo 上将此作为一个错误提交。 我认为它不太可能得到修复,但至少它会被记录在案。 如果它因Won't fix而关闭,您可能需要在文档中提交拉取请求,并注明这一点。

请注意, 当前代码实际上是以下代码,它以稍微不同的方式实现相同的东西。

            if (!FileSystem.FileExists(fullSourceFileName))
            {
                throw new FileNotFoundException(SR.Format(SR.IO_FileNotFound_FileName, fullSourceFileName), fullSourceFileName);
            }

            FileSystem.MoveFile(fullSourceFileName, fullDestFileName, overwrite);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM