首页 > 解决方案 > C# 应用程序搜索 System32 而不是本地文件

问题描述

我开发了一个 C# winforms 应用程序。该应用程序需要另一个文件才能运行,该文件与可执行文件位于同一目录中。让我们调用这个文件a.abc。当我使用命令提示符时,导航到程序目录,然后键入以下内容以使用我的程序打开文件,它工作正常:

my-prog.exe "path-to-file\file-name"

但是,当我在资源管理器中右键单击文件,打开方式并选择我的程序时,由于某种原因,程序会尝试a.abcSystem32目录中而不是在应用程序目录中搜索文件。

在此处输入图像描述

我知道如果我使用完整的文件路径而不是使用相对路径,它会正常工作,但我想知道为什么会这样?

更新#1

我有一个reqdFileName以值命名的字符串资源toolset.f

我正在使用

using (StreamReader sr = File.OpenText(@Properties.Resources.reqdFileName))
    // read lines and use it here
}

标签: c#.netfile

解决方案


这都是关于绝对和相对路径的。由于您的路径是相对的,因此它与您的进程工作目录“前置” 。

因此,当您在应用程序目录(例如C:\MyProgram\)中运行程序时 - 路径a.abc等于C:\MyProgram\a.abc. 如果你C:\像这样从不同的目录(比如 )运行它:.\MyProgram\my-prog.exe,那么 patha.abc等于C:\a.abc. 您可以通过自行检查的System.IO.Directory.GetCurrentDirectory() 方法获取当前工作目录。

当您使用“打开方式”菜单时 - 您的当前目录将是%windir%\system32并且这是“按设计”,您不应该尝试更改它。


您可以通过将相对路径转换为绝对路径来解决您的问题,如下所示:

using System.Reflection;
using System.IO;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
var reqdFilePath = Path.Combine(appPath, @Properties.Resources.reqdFileName);
using (StreamReader sr = File.OpenText(reqdFilePath))
    // read lines and use it here
}

另一种选择是在程序开头的某处更改工作目录:

using System.Reflection;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
Directory.SetCurrentDirectory(appPath);
// we are in your app directory now for sure

// ... Later in your code ...
using (StreamReader sr = File.OpenText(@Properties.Resources.reqdFileName))
    // read lines and use it here
}

但是,在这种情况下,您应该在程序结束时以某种方式恢复您的工作目录,因为如果您的用户在最后强行移动到某个路径,这会让他们感到沮丧(如果您问我,我会讨厌这样的程序)。

在一些评论中还建议将您的应用程序目录添加到%PATH%evironment 变量。这可以解决问题,但是如果您显然不需要它,不要污染您的。不是无限的——是一个很好的解释。%PATH%%PATH%


只是一个旁注。没有真正需要处理流和流读取器来逐行读取文件。有一个File.ReadAllLines() 方法

using System.Reflection;
using System.IO;

var appLocation = Assembly.GetEntryAssembly().Location;
var appPath = Path.GetDirectoryName(appLocation);
var reqdFilePath = Path.Combine(appPath, @Properties.Resources.reqdFileName);
foreach (var line in File.ReadAllLines(reqdFilePath))
{
    // use your line here
}

正如我所说,它将逐行读取,因此可以读取一个大文件(它不会将整个文件加载到您的内存中,一次只加载一行)。如果您的文件不是那么大,您也可以一次性将其全部读取为单个stringwithFile.ReadAllText() 方法


推荐阅读