¿Cómo puedo extraer el nombre del archivo y la extensión de una ruta de acceso en C++


Tengo una lista de archivos almacenados en un .log en esta sintaxis:

c:\foto\foto2003\shadow.gif
D:\etc\mom.jpg

Quiero extraer el nombre y la extensión de estos archivos. ¿Puede dar un ejemplo de una manera sencilla de hacer esto?

Author: Kiril Kirov, 2010-12-13

8 answers

Para extraer un nombre de archivo sin extensión, use boost::filesystem::path:: stem en lugar de ugly 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
 142
Author: Nickolay Merkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-17 11:00:40

Si desea una forma segura (es decir, portátil entre plataformas y no poner suposiciones en el camino), le recomendaría usar boost::filesystem.

De alguna manera se vería así:

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

Entonces puede extraer varios datos de esta ruta. Aquí está la documentación del objeto path.


POR cierto: También recuerda que para usar path como

c:\foto\foto2003\shadow.gif

Necesitas escapar del \ en un literal de cadena:

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

O use / en su lugar:

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

Esto solo se aplica a especificar cadenas literales en comillas "", el problema no existe cuando se cargan rutas desde un archivo.

 19
Author: Kos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-13 16:12:21

Tendrá que leer sus nombres de archivo desde el archivo en std::string. Puede utilizar el operador de extracción de cadenas de std::ostream. Una vez que tenga su nombre de archivo en un 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  = "";
    }
}
 13
Author: Sylvain Defresne,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-01-22 01:35:19

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"

Referencia sobre el 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 comillas, por ejemplo:

filename and extension: "file.ext"

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

filename and extension: file.ext
 8
Author: Yuchen Zhong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-12 15:30:36

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

  1. Read a std::string from the input stream (std::ifstream), each instance read will be the full path
  2. Hacer un find_last_of en la cadena para el \
  3. Extraiga una subcadena de esta posición hasta el final, esto le dará el nombre de archivo
  4. Haz un find_last_of para ., y una subcadena a cada lado te dará nombre + extensión.
 3
Author: Nim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-12-13 16:10:58

También uso este fragmento para determinar el carácter de barra diagonal apropiado:

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

Y luego reemplace las barras con la barra preferida para el sistema operativo. Útil si se está implementando constantemente entre Linux / Windows.

 0
Author: svanschalkwyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-16 16:29:07

Para máquinas linux o unix, el sistema operativo tiene dos funciones que tratan con nombres de ruta y archivos. utilice man 3 basename para obtener más información sobre estas funciones. La ventaja de usar la funcionalidad provista por el sistema es que no tiene que instalar boost ni tener que escribir sus propias funciones.

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

Código de ejemplo de la página de manual:

   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-const de la función basename (), es un poco no sencillo usar esto dentro de C++ codificar. He aquí un ejemplo sencillo 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 intento/captura bloquear en caso de que algo pasó entre las dos llamadas.

 0
Author: Kemin Zhou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-07 22:39:10

Las respuestas de Nickolay Merkin y Yuchen Zhong son geniales, pero sin embargo de los comentarios se puede ver que no es completamente precisa.

La conversión implícita a std::string al imprimir envolverá el nombre del archivo entre comillas. Los comentarios tampoco son precisos.

path::filename() y path::stem() devuelve un nuevo objeto path y path::string() devuelve una referencia a una cadena. Por lo tanto, algo como std::cout << file_path.filename().string() << "\n" podría causar problemas con la referencia colgando ya que la cadena a la que los puntos de referencia podrían han sido destruidos.

 0
Author: Nicholas Mulianto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-10-02 04:10:28