11

我正在使用 C# 在 Visual Studio 2010 中编写此 Windows 窗体应用程序。

表单上有一个执行按钮,用户点击该按钮,程序将生成一些文件并存储在Output文件夹中(由程序使用创建Directory.CreateDirectory()

我想创建一个存档文件夹来保存以前运行的输出文件。

在每次运行开始时,我尝试将现有Output文件夹移动到该Archive文件夹​​,然后创建一个新Output文件夹。下面是我运行移动目录的函数。

static void moveToArchive()
{
    if (!Directory.Exists("Archive")) Directory.CreateDirectory("Archive");
    string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
    try
    {
        Directory.Move("Output", "Archive\\" + timestamp);
    }
    catch(Exception e)
    {
        Console.WriteLine("Can not move folder: " + e.Message);
    }
}

我遇到的问题让我很困惑......

有时我可以成功地将输出文件夹移动到存档,但有时会失败。

我从捕获异常中得到的错误消息是Access to path 'Output' is denied.

我检查了文件Output夹中的所有文件都没有被使用。我不明白访问是如何被拒绝的,有时而不是所有时间。

有人可以向我解释并告诉我如何解决问题吗?

- 编辑 -

在 HansPassant 评论之后,我稍微修改了函数以获取当前目录并使用完整路径。但是,我仍然遇到同样的问题。

该函数现在看起来像这样:

static void moveToArchive()
{
    string currentDir = Environment.CurrentDirectory;
    Console.WriteLine("Current Directory = " + currentDir);
    if (!Directory.Exists(currentDir + "\\Archive")) Directory.CreateDirectory(currentDir + "\\Archive");
    string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
    try
    {
        Directory.Move(currentDir + "\\Output", currentDir + "\\Archive\\" + timestamp);
    }
    catch(Exception e)
    {
        Console.WriteLine("Can not move folder: " + e.Message);
    }
}

我打印出当前目录,它正如我所期望的那样,但我仍然无法使用完整路径。Access to path 'C:\Users\Me\Desktop\FormApp\Output' is denied.

- 编辑 -

谢谢大家的回答和评论。

我想你们中的一些人会错过这部分,所以我要再强调一点。

Directory.Move() 有时有效,有时失败。

当函数成功时,就没有问题了。Output文件夹移动到Archive

当函数失败时,我得到的异常消息是拒绝访问路径。

4

7 回答 7

14

谢谢大家的回复和帮助。我已经弄清楚问题所在了。

这是因为有一个文件没有完全关闭。

我正在检查生成的文件,并错过了程序正在读取的文件。

生成的所有文件都已完全关闭。这是我曾经StreamReader打开但没有关闭的一个文件。我修改了代码,现在没有问题,所以我认为这就是问题所在。

感谢所有的评论和答案,这绝对有助于我思考和解决问题。

于 2013-09-23T18:52:06.437 回答
4

http://windowsxp.mvps.org/processlock.htm

有时,您尝试移动或删除文件或文件夹并收到访问冲突或文件正在使用 - 错误。要成功删除文件,您需要识别锁定文件的进程。您需要先退出该过程,然后删除特定文件。要知道哪个进程锁定了文件,您可以使用本文中讨论的方法之一。

使用 Process Explorer - 从 http://download.sysinternals.com/files/ProcessExplorer.zip下载

Process Explorer 向您显示有关哪些句柄和 DLL 进程已打开或加载的信息。

从 Microsoft 站点下载 Process Explorer 并运行该程序。单击 Find 菜单,然后选择 Find Handle 或 DLL... 键入文件名(被某个进程锁定的文件的名称。)键入搜索短语后,单击 Search 按钮 您应该会看到应用程序列表访问文件。

于 2013-09-20T23:46:38.500 回答
2

我最近碰到了同样的问题。使用 PE,我发现使用该特定目录的唯一进程是 explorer.exe。我用资源管理器打开了几个窗口,一个指向我要移动的一个的父目录。

看来,在我访问该子文件夹然后返回(甚至返回到根级别!)之后,资源管理器仍保留该句柄,因此 C# 无法以任何方式修改它(更改标志、属性等)。

为了使 C# 正常运行,我不得不杀死那个资源管理器窗口。

于 2013-12-12T09:56:48.657 回答
1
File.SetAttributes(Application.dataPath + "/script", FileAttributes.Normal);
Directory.Move(Application.dataPath + "/script", Application.dataPath + "/../script");

这解决了我的问题。

于 2017-11-09T13:07:23.653 回答
0

试试这个:如果这不能解决,可能检查/更改防病毒软件,或者其他一些程序正在锁定某些文件或文件夹。

    static object moveLocker = new object();
    static void moveToArchive()
    {
        lock (moveLocker)
        {
            System.Threading.Thread.Sleep(2000);  // Give sometime to ensure all file are closed.

            //Environment.CurrentDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
            string applicationPath = System.AppDomain.CurrentDomain.BaseDirectory;
            string archiveBaseDirectoryPath = System.IO.Path.Combine(applicationPath, "Archive");

            if (!Directory.Exists(archiveBaseDirectoryPath)) Directory.CreateDirectory(archiveBaseDirectoryPath);

            String timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
            String outputDirectory = System.IO.Path.Combine(Environment.CurrentDirectory, "Output");
            String destinationTS = System.IO.Path.Combine(archiveBaseDirectoryPath, timestamp);
            try
            {
                Directory.Move(outputDirectory, destinationTS);                
            }
            catch (Exception ex)
            {
                Console.WriteLine("Can not move folder " + outputDirectory + " to: " + destinationTS + "\n" + ex.Message);
            }
        }
    }
于 2013-09-20T20:25:51.440 回答
0

我有一个类似的问题。遵循特定模板时,循环重命名了许多目录。程序有时会在不同的目录上崩溃。它有助于在 Directory.Move 之前添加一个睡眠线程。我需要制造一些延迟。但它会减慢复制过程。

foreach (var currentFullDirPath in Directory.GetDirectories(startTargetFullDirectory, "*", SearchOption.AllDirectories))
            {
                var shortCurrentFolderName = new DirectoryInfo(currentFullDirPath).Name.ToLower();
                if (shortCurrentFolderName.Contains(shortSourceDirectoryName))
                {
                    // Add Thread.Sleep(1000);
                    Thread.Sleep(1000);
                    var newFullDirName = ...;
                    Directory.Move(currentFullDirPath, newFullDirName);
                }
            }
于 2021-11-09T11:33:35.140 回答
0

我有同样的问题,它有时会失败,但并非总是如此。我以为我会将它包装在 Try Catch 块中,并向用户显示拒绝访问消息,一旦我将它包装在 Try Catch 块中,它就会停止失败。我无法解释为什么。

 If existingFile.FileName <> newFileName Then
    Dim dir As New IO.DirectoryInfo(existingFile.FilePath)
    Dim path As String = System.IO.Path.GetDirectoryName(dir.FullName)
    newFileName = path & "\" & newFileName

    File.SetAttributes(existingFile.FilePath, FileAttributes.Normal)
        Try
            IO.File.Move(existingFile.FilePath, newFileName)
        Catch ex As Exception

        End Try
End If
于 2020-04-14T09:16:29.897 回答