2010-12-13 9 views

Respuesta

126

Para extraer un nombre de archivo sin extensión, use impulso :: sistema de archivos :: :: ruta madre en lugar de feo std :: string :: find_last_of (".")

boost::filesystem::path p("c:/dir/dir/file.ext"); 
std::cout << "filename and extension : " << p.filename() << std::endl; // file.ext 
std::cout << "filename only   : " << p.stem() << std::endl;  // file 
+0

De acuerdo. Responde la pregunta de manera más sucinta. – AndyUK

+7

En realidad, p.filename() es de tipo ruta, y estará rodeado por comillas cuando se convierte implícitamente, por lo que obtendrá: nombre de archivo y extensión: "archivo.ext" Puede que desee p.filename(). cadena() en su lugar. –

+1

Con C++ 14/C++ 17 puede usar 'std :: experimental :: filesystem' resp' std :: filesystem'. Ver la publicación de Yuchen Zhong a continuación. –

3
No

el código, pero aquí es la idea:

  1. leer un std::string del flujo de entrada (std::ifstream), cada lectura instancia será la ruta completa
  2. Hacer un find_last_of en la cadena para el \
  3. Extraer una subcadena desde esta posición hasta el final, esto ahora le dará el nombre de archivo
  4. hacer un find_last_of para ., y una a cada lado subcadena voluntad darle nombre + extensión
+0

+1 para proporcionar la ayuda sin solo proporcionar el código. – razlebe

+0

Y -1 por ser no portátil :) – Kos

+0

¿Por qué votar abajo? Si hay algo mal con lo que dije, ¡házmelo saber y lo arreglaré! – Nim

19

Si quiere una forma segura (es decir, portátil entre plataformas y no poner suposiciones en la ruta), le recomiendo usar boost::filesystem.

Se vería alguna manera como esto:

boost::filesystem::path my_path(filename); 

A continuación, se puede extraer varios datos de este camino. Here's the documentation of path object.


BTW: También recuerda que con el fin de utilizar la ruta como

c:\foto\foto2003\shadow.gif 

que necesita para escapar de la \ en una cadena literal:

const char* filename = "c:\\foto\\foto2003\\shadow.gif"; 

O utilice / lugar:

const char* filename = "c:/foto/foto2003/shadow.gif"; 

Esto solo se aplica a la especificación de cadenas literales en "" comillas, el problema no existe cuando carga rutas desde un archivo.

+2

+1 Definitivamente el camino a seguir.El ejemplo en el sitio principal ofrece una forma de buscar un directorio: use el método path.extension() para buscar registros (consulte http://www.boost.org/doc/libs/1_36_0/libs/filesystem/doc/index .htm) – Tom

+0

De hecho, esto es en la mayoría de los casos el camino a seguir, sin embargo, implica agregar en algunos casos una dependencia indeseable en una biblioteca externa. Si quiere trabajar solo en lo que proporciona el estándar C++, le sugiero que busque en el regex de C++, donde puede definir una expresión regular para hacer lo que quiera (muchos ejemplos en Internet). La ventaja: sin gastos adicionales debido a algunas dependencias adicionales. Sin embargo, esto también deja una pregunta abierta: ¿se requiere multiplataforma? Boost cuida el estilo de ruta sin importar si está usando Windows o Linux. Usando regex, tienes que hacer eso por tu cuenta. – rbaleksandar

13

Tendrás que leer los nombres de tus archivos del archivo en std::string. Puede usar el operador de extracción de cadena std::ostream. Una vez que tenga su nombre de archivo en std::string, puede usar el método std::string::find_last_of para encontrar el último separador.

Algo como esto:

std::ifstream input("file.log"); 
while (input) 
{ 
    std::string path; 
    input >> path; 

    size_t sep = path.find_last_of("\\/"); 
    if (sep != std::string::npos) 
     path = path.substr(sep + 1, path.size() - sep - 1); 

    size_t dot = path.find_last_of("."); 
    if (dot != std::string::npos) 
    { 
     std::string name = path.substr(0, dot); 
     std::string ext = path.substr(dot, path.size() - dot); 
    } 
    else 
    { 
     std::string name = path; 
     std::string ext = ""; 
    } 
} 
+0

No quiero ser inteligente, pero debería ser path.substr y no path.substring, ¿verdad? –

0

también utilizo este fragmento para determinar el carácter de barra apropiada:.

boost::filesystem::path slash("/"); 
    boost::filesystem::path::string_type preferredSlash = slash.make_preferred().native(); 

y luego vuelva a colocar las barras con la barra preferido para el sistema operativo Útil si uno está en constante despliegue de entre Linux/. ventanas

6

Para C++ 17:

#include <filesystem> 

std::filesystem::path p("c:/dir/dir/file.ext"); 
std::cout << "filename and extension: " << p.filename() << std::endl; // "file.ext" 
std::cout << "filename only: " << p.stem() << std::endl;    // "file" 

de referencia acerca de sistema de archivos: http://en.cppreference.com/w/cpp/filesystem


Como sugiere @RoiDanto, para el formato de salida, std::out puede rodear la salida con citas, por ejemplo:

filename and extension: "file.ext" 

Puede convertir std::filesystem::path-std::string por p.filename().string() si eso es lo que necesita, por ejemplo .:

filename and extension: file.ext 
+0

¡Hola @RoiDanton, gracias por la edición! Acabo de comprobar el código de ejemplo en el enlace de referencia de nuevo, no parece que sea necesario convertir el tipo de retorno de 'std :: filesystem :: path' a' std :: string' para poder usar 'std :: cout'. http://en.cppreference.com/w/cpp/filesystem/path/filename Pero si piensas lo contrario, no dudes en comentar o editar la publicación nuevamente. –

+0

Eso es cierto, 'std :: cout' puede confiar en la conversión implícita. Sin embargo, como los comentarios posteriores a 'std :: cout' dicen file.ext y file, se debe agregar' .string() 'a los comentarios o deben ser" file.ext "y" file ". Con Visual C++ no hay diferencia (incluso sin 'string()' el resultado es sin comillas), pero con gcc 6.1 la salida está entre comillas si se omite '.string()'. Ver http://coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3 –

+0

@RoiDanton, hey, eso es una idea interesante. Actualizaré la publicación nuevamente. ¡Gracias por compartir esto! –

0

Para las máquinas Linux o UNIX, el sistema operativo tiene dos funciones relacionadas con los nombres de ruta y de archivo. use man 3 basename para obtener más información sobre estas funciones. La ventaja de usar la funcionalidad proporcionada por el sistema es que no tiene que instalar el refuerzo o la necesidad de escribir sus propias funciones.

#include <libgen.h> 
     char *dirname(char *path); 
     char *basename(char *path); 

código Ejemplo de la página man:

char *dirc, *basec, *bname, *dname; 
      char *path = "/etc/passwd"; 

      dirc = strdup(path); 
      basec = strdup(path); 
      dname = dirname(dirc); 
      bname = basename(basec); 
      printf("dirname=%s, basename=%s\n", dname, bname); 

Debido al tipo de argumento no constante de la función basename(), es un poco no recto hacia adelante utilizando esta dentro de código C++ . Aquí hay un ejemplo simple de mi código base:

string getFileStem(const string& filePath) const { 
    char* buff = new char[filePath.size()+1]; 
    strcpy(buff, filePath.c_str()); 
    string tmp = string(basename(buff)); 
    string::size_type i = tmp.rfind('.'); 
    if (i != string::npos) { 
     tmp = tmp.substr(0,i); 
    } 
    delete[] buff; 
    return tmp; 
} 

El uso de nuevo/eliminar no es un buen estilo. Podría haberlo puesto en un bloque try/catch en caso de que algo ocurriera entre las dos llamadas.

Cuestiones relacionadas