2010-10-04 9 views
47

Si ejecuto un proceso con ShellExecute (o en .net con System.Diagnostics.Process.Start()), no es necesario que el proceso del nombre de archivo sea una ruta completa.Compruebe si existe un archivo ejecutable en la ruta de Windows

Si quiero empezar el bloc de notas, puedo usar

Process.Start("notepad.exe"); 

en lugar de

Process.Start(@"c:\windows\system32\notepad.exe"); 

porque el direcotry c:\windows\system32 forma parte de la variable de entorno PATH.

¿cómo puedo comprobar si existe un archivo en la RUTA sin ejecutar el proceso y sin analizar la variable PATH?

System.IO.File.Exists("notepad.exe"); // returns false 
(new System.IO.FileInfo("notepad.exe")).Exists; // returns false 

pero necesito algo como esto:

System.IO.File.ExistsOnPath("notepad.exe"); // should return true 

y

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

¿Hay una clase predefinida hacer disponible en el BCL esta tarea?

+0

Si bien dicha clase predefinida sería conveniente (o es conveniente, si es que existe) no es solo hay una línea más para obtener el camino, luego verificamos existe()? Podrías haberlo escrito más rápido que hacer la pregunta. ¿Razón/necesidad especial? Sólo me preguntaba. – mickeyf

+2

Yepp, debería ser muy fácil. Pero mi convicción es que, si se puede hacer una tarea con la biblioteca existente de un lenguaje de probramming, estoy de acuerdo con reinventar el weel una y otra vez. Si no hay algo disponible, lo hago solo. –

Respuesta

44

creo que no hay nada incorporado, pero se podría hacer algo como esto con 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(';')) 
    { 
     var fullPath = Path.Combine(path, fileName); 
     if (File.Exists(fullPath)) 
      return fullPath; 
    } 
    return null; 
} 
+3

Si va a hacer esto, sugiero convertirlos en métodos de extensión ... http: //msdn.microsoft.com/en-us/library/bb383977.aspx –

+5

@ Aaron: ¿Está seguro de que verá 'GetFullPath 'como método de extensión para' cadena'? Me sonaría extraño ... Tal vez podría tener sentido para 'FileInfo' ... – digEmAll

+0

Sí, sería extraño cuando use una cadena. Sin embargo, creo que tendría sentido ajustar la funcionalidad anterior de ambos métodos en un único método de extensión titulado ExistsOnPath que cuelga de FileInfo como usted mencionó. –

22

Esto es riesgoso, hay mucho más a él que simplemente buscar los directorios en el PATH. Prueba esto:

Process.Start("wordpad.exe"); 

El ejecutable se almacena en c: \ Archivos de programa \ Windows NT \ Accesorios en mi máquina, ese directorio es no en el camino.

Las teclas HKCR \ Applications y HKLM \ SOFTWARE \ Microsoft \ Windows \ CurrentVersion \ App Paths también desempeñan un papel en la búsqueda de ejecutables. Estoy bastante seguro de que hay más minas terrestres como esta, la virtualización de directorios en versiones de 64 bits de Windows podría hacer que te tropieces, por ejemplo.

Para hacer esto más confiable, creo que necesita pinvoke AssocQueryString(). No estoy seguro, nunca tuve la necesidad. El mejor enfoque es sin duda no tener que hacer la pregunta.

+0

la aplicación que quiero la consulta se registra en la ruta (mysqldump.exe). Si no, o si no está instalado, quiero deshabilitar la opción de usar mysqlbackup desde una aplicación de formularios de Windows. Simplemente no quiero codificar el camino al archivo. –

+0

Es * muy * raro en estos días que los instaladores modifiquen la RUTA. Especialmente para una utilidad, verifique eso primero. Solo usaría una configuración con el alcance de la aplicación y el valor predeterminado para "" aquí. –

+3

Este fue el tema de una reciente publicación de Raymond Chen. Difícil superar sus habilidades de blogging, aparte de que yo era el primero. Disfruta: http://blogs.msdn.com/b/oldnewthing/archive/2011/07/25/10189298.aspx –

2

Estoy buscando lo mismo y creo que la mejor opción que tengo ahora es utilizar llamadas nativas a CreateProcess para crear un proceso suspendido y ver el éxito; terminando el proceso inmediatamente después. Terminar un proceso suspendido no debe incurrir en ningún recurso sangrado [citación necesitada]]

Puede que no sea capaz de averiguar la ruta que realmente se usó, pero para un requisito simple como ExistsOnPath() debería hacer, hasta que haya una mejor solución.

9

Ok, creo que es una mejor manera ...

Este utiliza el comando donde, que está disponible al menos en Windows 7/Server 2003:

public static bool ExistsOnPath(string exeName) 
{ 
    try 
    { 
     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 
    { 
     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"); 
    } 
} 
Cuestiones relacionadas