Obtener un nombre de directorio a partir de un nombre de archivo


85

Tengo un nombre de archivo (C: \ carpeta \ foo.txt) y necesito recuperar el nombre de la carpeta (C: \ carpeta) en C ++ no administrado. En C # haría algo como esto:

string folder = new FileInfo("C:\folder\foo.txt").DirectoryName;

¿Existe una función que se pueda usar en C ++ no administrado para extraer la ruta del nombre del archivo?

Respuestas:


20

Hay una función estándar de Windows para esto, PathRemoveFileSpec . Si solo es compatible con Windows 8 y versiones posteriores, se recomienda encarecidamente utilizar PathCchRemoveFileSpec en su lugar. Entre otras mejoras, ya no se limita a MAX_PATH(260) caracteres.


2
Tenga en cuenta que esta función ahora está obsoleta. La sugerencia de Microsoft es utilizar PathCchRemoveFileSpec en su lugar.
defecto el

1
@Default: PathCchRemoveFileSpec solo está disponible a partir de Windows 8. Dado que Windows Vista y 7 todavía son compatibles, también lo es PathRemoveFileSpec .
Inspectable

153

Usando Boost.Filesystem:

boost::filesystem::path p("C:\\folder\\foo.txt");
boost::filesystem::path dir = p.parent_path();

2
p.remove_filename()se modificará pen el lugar y puede implementarse de manera más eficiente quep = p.parent_path()
Peter Cordes

Si también puede trabajar con directorios, tenga en cuenta el hecho de que parent_path()de "C:\\folder"resultará en "C:".
Semjon Mössinger

mucho impulso se actualiza a std así que también intente esto .... incluir <filesystem> .... std :: experimental :: filesystem :: path p ("C: \\ folder \\ foo.txt");
S Meaden

72

Ejemplo de http://www.cplusplus.com/reference/string/string/find_last_of/

// string::find_last_of
#include <iostream>
#include <string>
using namespace std;

void SplitFilename (const string& str)
{
  size_t found;
  cout << "Splitting: " << str << endl;
  found=str.find_last_of("/\\");
  cout << " folder: " << str.substr(0,found) << endl;
  cout << " file: " << str.substr(found+1) << endl;
}

int main ()
{
  string str1 ("/usr/bin/man");
  string str2 ("c:\\windows\\winhelp.exe");

  SplitFilename (str1);
  SplitFilename (str2);

  return 0;
}

1
Esta es la mejor solución mínima aquí.
plasmacel

39

En C ++ 17 existe una clase que std::filesystem::pathusa el método parent_path.

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
    for(fs::path p : {"/var/tmp/example.txt", "/", "/var/tmp/."})
        std::cout << "The parent path of " << p
                  << " is " << p.parent_path() << '\n';
}

Salida posible:

The parent path of "/var/tmp/example.txt" is "/var/tmp"
The parent path of "/" is ""
The parent path of "/var/tmp/." is "/var/tmp"

2
También existe un .remove_filename()método.
Qqwy

1
Gracias, @Qqwy, también permite usar la ruta del directorio con ese método para obtener resultados correctos y esperados a diferencia del enfoque de la respuesta
Herrgott

13

¿Por qué tiene que ser tan complicado?

#include <windows.h>

int main(int argc, char** argv)         // argv[0] = C:\dev\test.exe
{
    char *p = strrchr(argv[0], '\\');
    if(p) p[0] = 0;

    printf(argv[0]);                    // argv[0] = C:\dev
}

10
Esto no es portátil. El separador de ruta en Linux es '/'. std :: filesystem :: path es estándar y portátil.
Rémi

7
 auto p = boost::filesystem::path("test/folder/file.txt");
 std::cout << p.parent_path() << '\n';             // test/folder
 std::cout << p.parent_path().filename() << '\n';  // folder
 std::cout << p.filename() << '\n';                // file.txt

Es posible que deba p.parent_path().filename()obtener el nombre de la carpeta principal.


5

Utilice boost :: filesystem. Se incorporará en el siguiente estándar de todos modos, por lo que es mejor que se acostumbre a él.


1
¿De qué estándar estás hablando? Sé que se agregaron muchas cosas de boost a C ++ std lib, ¿también se agregará el sistema de archivos?
McLeary

7
"Se incorporará en el próximo estándar de todos modos" Y no lo es
Anton K

@AntonK tal vez C ++ 2017?
Alessandro Jacopson

6
@AlessandroJacopson Genial, parece incluido en C ++ 17 - en.cppreference.com/w/cpp/filesystem
Anton K


1

Estoy tan sorprendido de que nadie haya mencionado la forma estándar en Posix

Utilice basename / dirnameconstrucciones.

hombre nombre de base


Las funciones POSIX no están exentas de inconvenientes. En particular, pueden modificar el búfer que pasa, (realmente quieren decir que la firma es basname(char * path)y no basename(const char * path)), y las implementaciones que no lo hacen parecen tener que usar un búfer estático que los hace inseguros para subprocesos (en principio, usted también podría devolver resultados asignados dinámicamente, pero eso lo hace dependiente de allocfunciones familiares, lo cual es incómodo en C ++).
dmckee --- ex-moderador gatito

-1

C ++ estándar no hará mucho por usted en este sentido, ya que los nombres de ruta son específicos de la plataforma. Puede analizar manualmente la cadena (como en la respuesta de glowcoder), usar las funciones del sistema operativo (por ejemplo, http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx ), o probablemente el mejor enfoque, puede utilizar una biblioteca de sistema de archivos de terceros como boost :: filesystem.


El C ++ 1z del estándar está intentando adoptar la biblioteca del sistema de archivos boost a partir de ahora, haciendo que la compatibilidad con la plataforma sea un problema mucho menor. Todavía está en los encabezados experimentales de MSVC, al menos.
kayleeFrye_onDeck

-6

Simplemente use esto: ExtractFilePath (your_path_file_name)


5
Creo que este es un método Delphi, no algo en C ++.
Ian Hunter
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.