检查Windows路径中是否存在可执行文件

Jür*_*ock 56 .net c# file

如果我使用ShellExecute(或在.net中System.Diagnostics.Process.Start())运行进程,则启动文件名进程不需要是完整路径.

如果我想开始记事本,我可以使用

Process.Start("notepad.exe");
Run Code Online (Sandbox Code Playgroud)

代替

Process.Start(@"c:\windows\system32\notepad.exe");
Run Code Online (Sandbox Code Playgroud)

因为direcotry c:\windows\system32是PATH环境变量的一部分.

如何在不执行进程且不解析PATH变量的情况下检查PATH上是否存在文件?

System.IO.File.Exists("notepad.exe"); // returns false
(new System.IO.FileInfo("notepad.exe")).Exists; // returns false
Run Code Online (Sandbox Code Playgroud)

但我需要这样的东西:

System.IO.File.ExistsOnPath("notepad.exe"); // should return true
Run Code Online (Sandbox Code Playgroud)

System.IO.File.GetFullPath("notepad.exe"); // (like unix which cmd) should return
                                           // c:\windows\system32\notepad.exe
Run Code Online (Sandbox Code Playgroud)

是否有预定义的类可以在BCL中执行此任务?

dig*_*All 57

我认为没有任何内置功能,但您可以使用System.IO.File.Exists执行类似的操作:

public static bool ExistsOnPath(string fileName)
{
    return GetFullPath(fileName) != null;
}

public static string GetFullPath(string fileName)
{
    if (File.Exists(fileName))
        return Path.GetFullPath(fileName);

    var values = Environment.GetEnvironmentVariable("PATH");
    foreach (var path in values.Split(Path.PathSeparator))
    {
        var fullPath = Path.Combine(path, fileName);
        if (File.Exists(fullPath))
            return fullPath;
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

  • @Aaron:你确定你会看到`GetFullPath`作为`string`的扩展方法吗?这对我来说听起来很奇怪...也许对于'FileInfo`有意义...... (6认同)
  • @Aaron:由于几个原因(例如,为什么我必须通过FileInfo,如果我只需要一个字符串......),我仍然喜欢它们作为静态方法,可能包含在Utilities静态类中,但我明白这可能是有争议的..无论如何,对于提问者来说,很容易在Extension方法中转换上面的代码;) (5认同)
  • 这段代码不能移植到其他平台,在Unix上你需要使用`Path.PathSeparator`而不是硬编码半冒号. (4认同)
  • 如果您打算这样做,我建议将这些转换为扩展方法... http://msdn.microsoft.com/en-us/library/bb383977.aspx (3认同)

Han*_*ant 27

这是有风险的,除了在PATH中搜索目录之外还有很多其他内容.试试这个:

 Process.Start("wordpad.exe");
Run Code Online (Sandbox Code Playgroud)

可执行文件存储在我的机器上的c:\ Program Files\Windows NT\Accessories中,该目录不在路径上.

HKCR\Applications和HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths键也在查找可执行文件中发挥作用.我相当确定有这样的地雷,64位版本的Windows中的目录虚拟化可能会让你失望.

为了使这更可靠,我认为你需要pinvoke AssocQueryString().不确定,从来没有必要.更好的方法当然不必提问.

  • 这是最近Raymond Chen职位的主题.除了我第一次,很难打败他的博客技巧.享受:http://blogs.msdn.com/b/oldnewthing/archive/2011/07/25/10189298.aspx (5认同)
  • 更新了 Raymond Chen 帖子的链接:https://devblogs.microsoft.com/oldnewthing/20110725-00/?p=10073 (2认同)

Dun*_*unc 16

好吧,我认为更好的方式......

这使用where命令,该命令至少在Windows 7/Server 2003上可用:

public static bool ExistsOnPath(string exeName)
{
    try
    {
        using (Process p = new Process())
        {
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.FileName = "where";
            p.StartInfo.Arguments = exeName;
            p.Start();
            p.WaitForExit();
            return p.ExitCode == 0;
        }
    }
    catch(Win32Exception)
    {
        throw new Exception("'where' command is not on path");
    }
}

public static string GetFullPath(string exeName)
{
    try
    {
        using (Process p = new Process())
        {
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.FileName = "where";
            p.StartInfo.Arguments = exeName;
            p.StartInfo.RedirectStandardOutput = true;
            p.Start();
            string output = p.StandardOutput.ReadToEnd();
            p.WaitForExit();

            if (p.ExitCode != 0)
                return null;

            // just return first match
            return output.Substring(0, output.IndexOf(Environment.NewLine));
        }
    }
    catch(Win32Exception)
    {
        throw new Exception("'where' command is not on path");
    }
}
Run Code Online (Sandbox Code Playgroud)


Eug*_*ala 6

接受的答案表明没有任何内置,但事实并非如此.有一个标准的WinAPI PathFindOnPath用于执行此操作,它从Windows 2000开始可用.


Ron*_*Ron 6

我尝试了Dunc的"where"过程并且它有效,但它很慢且资源很重,并且存在孤立进程的轻微危险.

我喜欢Eugene Mala关于PathFindOnPath的提示,因此我将其作为一个完整的答案充实.这就是我用于自定义内部工具的内容.

/// <summary>
/// Gets the full path of the given executable filename as if the user had entered this
/// executable in a shell. So, for example, the Windows PATH environment variable will
/// be examined. If the filename can't be found by Windows, null is returned.</summary>
/// <param name="exeName"></param>
/// <returns>The full path if successful, or null otherwise.</returns>
public static string GetFullPathFromWindows(string exeName)
{
    if (exeName.Length >= MAX_PATH)
        throw new ArgumentException($"The executable name '{exeName}' must have less than {MAX_PATH} characters.",
            nameof(exeName));

    StringBuilder sb = new StringBuilder(exeName, MAX_PATH);
    return PathFindOnPath(sb, null) ? sb.ToString() : null;
}

// https://docs.microsoft.com/en-us/windows/desktop/api/shlwapi/nf-shlwapi-pathfindonpathw
// https://www.pinvoke.net/default.aspx/shlwapi.PathFindOnPath
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode, SetLastError = false)]
static extern bool PathFindOnPath([In, Out] StringBuilder pszFile, [In] string[] ppszOtherDirs);

// from MAPIWIN.h :
private const int MAX_PATH = 260;
Run Code Online (Sandbox Code Playgroud)