Como faço para obter o diretório que um programa está fugindo?
-
02-07-2019 - |
Pergunta
Existe um método independente de plataforma e sistema de arquivos agnóstica para obter o caminho completo do diretório de onde um programa está sendo executado usando C / C ++? Não deve ser confundido com o diretório de trabalho atual. (Por favor, não sugerem bibliotecas menos que eles são queridos padrão como clib ou STL).
(Se não há nenhum método de plataforma / filesystem-agnóstico, sugestões que funcionam em Windows e Linux para sistemas de arquivos específicos são bem-vindos também.)
Solução
código de aqui para obter o caminho completo para o aplicativo em execução:
Windows:
int bytes = GetModuleFileName(NULL, pBuf, len);
if(bytes == 0)
return -1;
else
return bytes;
Linux:
char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
int bytes = MIN(readlink(szTmp, pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;
Outras dicas
Se você buscar o diretório atual quando seu programa iniciado pela primeira vez, então você tem efetivamente o diretório seu programa foi iniciado a partir. Armazenar o valor em uma variável e se referem a ele mais tarde, em seu programa. Isso é diferente de o diretório que contém o atual arquivo executável programa . Não é necessariamente o mesmo diretório; se alguém executa o programa a partir de um prompt de comando, em seguida, o programa está sendo Executar diretório de trabalho atual do prompt de comando, mesmo que o arquivo de programa vive em outro lugar.
getcwd é uma função POSIX e apoiado fora da caixa por todas as plataformas compatíveis com POSIX. Você não teria que fazer nada especial (além de incliding os cabeçalhos corretos unistd.h em Unix e direct.h no Windows).
Como você está criando um programa em C que irá ligar com o padrão c biblioteca de tempo de execução que está ligado ao por todos os processos no sistema (especialmente exceções evitados trabalhada) e vai incluir esta função por padrão. A CRT nunca é considerado uma biblioteca externa, porque isso fornece a interface compatível com padrão básico para o sistema operacional.
No windows função getcwd foi preterido em favor de _getcwd. Eu acho que você poderia usá-lo desta forma.
#include <stdio.h> /* defines FILENAME_MAX */
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
Esta é a partir do cplusplus fórum
No Windows:
#include <string>
#include <windows.h>
std::string getexepath()
{
char result[ MAX_PATH ];
return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}
No Linux:
#include <string>
#include <limits.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
return std::string( result, (count > 0) ? count : 0 );
}
No HP-UX:
#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
struct pst_status ps;
if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
return std::string();
if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
return std::string();
return std::string( result );
}
Se você quiser uma maneira padrão sem bibliotecas: Não. Todo o conceito de um diretório não está incluído no padrão
Se você concorda que alguma dependência (portátil) em um lib quase-padrão é bem: Use biblioteca de sistema de arquivos do Boost e pedir a initial_path () .
IMHO que é o mais perto que se pode chegar, com um bom karma (Boost é um conjunto de alta qualidade bem estabelecida de bibliotecas)
Sistema de Ficheiros TS é agora um padrão (e suportada por gcc 5,3 + e clang 3.9+), assim você pode usar current_path()
função a partir dele :
std::string path = std::experimental::filesystem::current_path();
Em gcc (5.3+) para incluir sistema de arquivos que você precisa para uso:
#include <experimental/filesystem>
e ligar seu código com a bandeira -lstdc++fs
.
Se você quiser usar sistema de arquivos com o Microsoft Visual Studio, então ler este .
Eu sei que é muito tarde no dia para lançar uma resposta em um presente, mas eu achei que nenhuma das respostas eram tão útil para mim como a minha própria solução. Uma maneira muito simples para obter o caminho do seu CWD para a pasta bin é assim:
int main(int argc, char* argv[])
{
std::string argv_str(argv[0]);
std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}
Agora você pode apenas usar isso como uma base para o seu caminho relativo. Assim, por exemplo, eu tenho esta estrutura de diretórios:
main
----> test
----> src
----> bin
e eu quero compilar meu código-fonte para bin e escrever um log para testar posso apenas acrescentar esta linha ao meu código.
std::string pathToWrite = base + "/../test/test.log";
Eu tentei esta abordagem no Linux usando caminho completo, aliás, etc e ele funciona muito bem.
NOTA:
Se você estiver no Windows, você deve usar um '\' como separador de arquivo não '/'. Você terá que escapar isso também, por exemplo:
std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));
Eu acho que isso deve funcionar, mas não testei, então comentário seria apreciada se funciona ou uma correção se não.
Não, não há nenhuma maneira padrão. Eu acredito que as normas C / C ++ nem sequer considerar a existência de diretórios (ou outras organizações do sistema de arquivos).
No Windows GetModuleFileName () irá retornar o caminho completo para o arquivo executável do processo atual quando o hModule parâmetro é definido como NULL . Eu não posso ajudar com o Linux.
Além disso, você deve esclarecer se deseja que o diretório atual ou o diretório que a imagem programa / reside executáveis. Tal como está a sua pergunta é um pouco ambíguo sobre este ponto.
Talvez concatenar o diretório de trabalho atual com o argv [0]? Eu não tenho certeza se isso iria funcionar no Windows, mas ele funciona em Linux.
Por exemplo:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
char the_path[256];
getcwd(the_path, 255);
strcat(the_path, "/");
strcat(the_path, argv[0]);
printf("%s\n", the_path);
return 0;
}
Quando executado, ele gera:
Jeremy @ Jeremy-desktop: ~ / Desktop $ ./test
/ Home / Jeremy / Desktop /./ teste
Você não pode usar argv [0] para o efeito, geralmente ele contém caminho completo para o executável, mas não nessesarily - processo poderia ser criado com valor arbitrário no campo.
Também lembre-se, o diretório atual eo diretório com o executável são duas coisas diferentes, de modo getcwd () não vai ajudá-lo a qualquer um.
No Windows uso GetModuleFileName (), no Linux ler / dev / proc / procID / .. arquivos.
No Windows a maneira mais simples é usar a função _get_pgmptr
em stdlib.h
para obter um ponteiro para uma string que representa o caminho absoluto para o executável, incluindo o nome executáveis.
char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
Para Win32 GetCurrentDirectory deve fazer o truque .
Apenas a pilha tardiamente aqui, ...
não há uma solução padrão, porque as línguas são agnósticos de sistemas de arquivos subjacentes, assim como já foi dito, o conceito de um sistema de arquivos baseado em diretório está fora do escopo de C / C ++ idiomas.
Em cima disso, você não quer que o diretório de trabalho atual, mas o diretório o programa está sendo executado em, que deve levar em conta a forma como o programa chegou ao ponto onde ele é - ou seja, foi gerado como um novo processo através de um garfo , etc. Para obter o diretório de um programa está sendo executado em, como as soluções têm demonstrado, requer que você obter essa informação a partir das estruturas do sistema operacional em questão, que é a única autoridade sobre esta questão de controle de processo. Assim, por definição, seu uma solução OS específico.
Para o sistema do Windows no console, você pode usar o comando do sistema (dir
). Eo console fornece informações sobre diretório e etc. Leia sobre o comando dir
em cmd
. Mas para Unix-like sistemas, eu não sei ... Se este comando é executado, leia comando bash. ls
diretório não exibe ...
Exemplo:
int main()
{
system("dir");
system("pause"); //this wait for Enter-key-press;
return 0;
}
#include <windows.h>
using namespace std;
// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
char currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
return string(currentDir);
}
O comando bash linux que progname irá relatar um caminho para programa.
Ainda que se pudesse emitir o qual comando de dentro de seu programa e direcionar a saída para um arquivo tmp eo programa posteriormente lê esse arquivo tmp, não vai dizer se esse programa é a execução. Ele só lhe diz onde um programa com esse nome está localizado.
O que é necessário é obter o seu número de ID do processo, e para analisar o caminho para o nome
No meu programa eu quero saber se o programa foi executado a partir do diretório bin do usuário ou de outro no caminho ou a partir de / usr / bin. / Usr / bin conteria a versão suportada. Meu sentimento é que no Linux não é a única solução que é portátil.
Por caminhos relativos, aqui está o que eu fiz. Estou ciente da idade esta pergunta, eu simplesmente querem contribuir com uma resposta mais simples que funciona na maioria dos casos:
Digamos que você tenha um caminho como este:
"path/to/file/folder"
Por alguma razão, executáveis ??Linux construídos feita em eclipse trabalho bem com isso. No entanto, o Windows fica muito confuso se for dado um caminho como este para trabalho com!
Como afirmado acima, existem várias maneiras de obter o caminho atual para o executável, mas o mais fácil achado maneira que eu trabalha um encanto na maioria dos casos é acrescentar isso à frente de seu caminho:
"./path/to/file/folder"
Basta adicionar "./" deverá fazê-lo resolvido! :) Então você pode começar a carregar a partir de qualquer diretório que você deseja, por isso, desde que seja com o executável em si.
EDIT: isto não vai funcionar se você tentar iniciar o executável a partir do código :: blocos se esse é o ambiente de desenvolvimento em uso, pois por alguma razão, Code :: Blocks não carrega direito material ...: D
EDIT2: Algumas coisas novas que tenho encontrado é que se você especificar um caminho estático como este em seu código (Assumindo Example.data é algo que você precisa de carga):
"resources/Example.data"
Se você, em seguida, iniciar o seu aplicativo a partir do diretório atual (ou no Windows, você fazer um atalho, e definir o dir trabalhando para o diretório app), em seguida, ele vai trabalhar assim. Tenha isso em mente ao depurar problemas relacionados à falta de caminhos de recursos / arquivo. (Especialmente em IDEs que definir o dir de trabalho errado ao lançar um exe construção do IDE)
Em plataformas POSIX, você pode usar getcwd () .
No Windows, você pode usar _getcwd () , como o uso de getcwd () foi substituído.
Para bibliotecas padrão, se impulso foram suficientes padrão para você, eu teria sugerido boost :: filesystem, mas eles parecem ter a normalização do caminho removida a proposta. Você pode ter que esperar até TR2 torna-se prontamente disponível para uma solução totalmente padrão.
Impulsione comporta initial_path()
do Sistema de arquivo como getcwd()
do POSIX, e nem faz o que quiser, por si só, mas acrescentando argv[0]
para qualquer um deles deve fazê-lo.
Você pode notar que o resultado não é sempre bonito - você pode obter coisas como /foo/bar/../../baz/a.out
ou /foo/bar//baz/a.out
, mas eu acredito que ele sempre resulta em um caminho válido que dá nome ao arquivo executável (note que cortes consecutivos em um caminho são recolhidos para um).
I anteriormente escreveu uma solução usando envp
(o terceiro argumento para main()
que trabalhou no Linux, mas não parece viável no Windows, então estou essencialmente recomendando a mesma solução que alguém fez anteriormente, mas com a explicação adicional de por isso que é realmente correto, mesmo que os resultados não são bonitas.
A Minok mencionado, não existe tal funcionalidade especificado padrão C ini ou C ++ padrão. Este é considerado puramente recurso específico do sistema operacional e está especificado no padrão POSIX, por exemplo.
Thorsten79 tem dado boa sugestão, é biblioteca Boost.Filesystem. No entanto, pode ser inconveniente no caso de você não quer ter quaisquer dependências link-time em formato binário para o seu programa.
Uma boa alternativa Eu recomendaria é uma coleção de 100% cabeçalhos somente STLSoft C ++ Bibliotecas Matthew Wilson (autor de livros de leitura obrigatória sobre C ++) . Não é portátil fachada PlatformSTL dá acesso a específicas do sistema API: WinSTL para Windows e UnixSTL em Unix, por isso é solução portátil. Todos os elementos específicos do sistema são especificados com o uso de traços e políticas, por isso é estrutura extensível. Há biblioteca de sistema de arquivos desde que, é claro.
A solução de biblioteca (embora eu sei que isso não foi solicitado).
Se acontecer de você usar Qt:
QCoreApplication::applicationDirPath()
Use realpath()
em stdlib.h
assim:
char *working_dir_path = realpath(".", NULL);
Funciona com a partir de C ++ 11, utilizando o sistema de arquivos experimental, e C ++ 14 C ++ 17 bem usando sistema de arquivos oficial.
application.h:
#pragma once
//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>
namespace std {
namespace filesystem = experimental::filesystem;
}
#endif
std::filesystem::path getexepath();
application.cpp:
#include "application.h"
#ifdef _WIN32
#include <windows.h> //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h> //readlink
#endif
std::filesystem::path getexepath()
{
#ifdef _WIN32
wchar_t path[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, path, MAX_PATH);
return path;
#else
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#endif
}