octaviano
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. ¿Puedes dar un ejemplo de una manera simple de hacer esto?
Para extraer un nombre de archivo sin extensión, use boost::filesystem::path::provenir 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
-
Acordado. Responde a la pregunta de la manera más sucinta.
– Andy Reino Unido
28 mayo 2014 a las 12:43
-
En realidad, p.filename() es del tipo ruta, y estará entre comillas cuando se convierta implícitamente, por lo que obtendrá: nombre de archivo y extensión: “file.ext” Es posible que desee p.filename().string() en su lugar.
–James Hirschorn
18 de febrero de 2016 a las 19:54
-
Con C++14/C++17 puedes usar
std::experimental::filesystem
resp.std::filesystem
. Vea la publicación de Yuchen Zhong a continuación.– Roi Dantón
12 de abril de 2017 a las 14:15
-
El autor de la pregunta quería una forma sencilla. Agregar impulso a un proyecto solo para esta funcionalidad no es una forma simple. std::filesystem es la forma más sencilla.
– KKlouzal
30 de noviembre de 2019 a las 13:26
-
C++17 incluyó
en la biblioteca estándar. Use un compilador nuevo… o importe boost. –Nicolay Merkin
2 de diciembre de 2019 a las 16:29
Yuchen
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 lo sugiere @RoiDantopara el formato de salida, std::out
puede rodear la salida con citas, por ejemplo:
filename and extension: "file.ext"
Puedes convertir std::filesystem::path
a std::string
por p.filename().string()
si eso es lo que necesitas, por ejemplo:
filename and extension: file.ext
-
Hola @RoiDanton, ¡gracias por la edición! Acabo de comprobar de nuevo el código de ejemplo en el enlace de referencia, no parece que sea necesario convertir el tipo de retorno de
std::filesystem::path
astd::string
para poder usarstd::cout
. en.cppreference.com/w/cpp/filesystem/path/filename Pero si piensas lo contrario, no dudes en comentar o editar la publicación nuevamente.– Yuchen
12 de abril de 2017 a las 14:39
-
Eso es cierto,
std::cout
puede confiar en la conversión implícita. Sin embargo, dado que los comentarios posterioresstd::cout
decir archivo.ext y archivo, ya sea.string()
debe agregarse a los comentarios o deben ser “archivo.ext” y “archivo”. Con Visual C++, de hecho, no hay diferencia (incluso sinstring()
la salida está sin comillas), pero con gcc 6.1 la salida está entre comillas si.string()
se omite. Ver coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3– Roi Dantón
12 de abril de 2017 a las 14:56
-
@RoiDanton, oye, esa es una idea interesante. Actualizaré la publicación nuevamente. ¡Gracias por compartir esto!
– Yuchen
12 de abril de 2017 a las 15:21
Si desea una forma segura (es decir, portátil entre plataformas y sin suposiciones en el camino), le recomiendo usar boost::filesystem
.
Se vería de alguna manera así:
boost::filesystem::path my_path( filename );
Luego puede extraer varios datos de esta ruta. Aquí está la documentación del objeto de ruta.
Por cierto: también recuerda que para usar una ruta como
c:\foto\foto2003\shadow.gif
tienes que escapar de la \
en un literal de cadena:
const char* filename = "c:\\foto\\foto2003\\shadow.gif";
O usar /
en cambio:
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.
-
+1 Definitivamente el camino a seguir. El ejemplo en el sitio principal da una forma de buscar un directorio: Use el método path.extension() para buscar registros (vea boost.org/doc/libs/1_36_0/libs/filesystem/doc/index.htm)
– Tomás
13 de diciembre de 2010 a las 16:18
-
De hecho, en la mayoría de los casos, este es el camino a seguir, sin embargo, implica agregar en algunos casos una dependencia no deseada en una biblioteca externa. Si desea trabajar solo con lo que proporciona el estándar C ++, le sugiero que consulte la expresión regular de C ++, donde puede definir una expresión regular para hacer lo que quiera (muchos ejemplos en Internet). La ventaja: sin gastos generales debido a algunas dependencias adicionales. Sin embargo, esto también deja una pregunta abierta: ¿se requiere multiplataforma? Boost se encarga del estilo de la ruta sin importar si está usando Windows o Linux. Usando expresiones regulares, tienes que hacerlo por tu cuenta.
– rbaleksandar
11 de julio de 2014 a las 20:13
Sylvain Defresne
Tendrá que leer sus nombres de archivo del 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
puedes usar el std::string::find_last_of
método 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 = "";
}
}
No es el código, pero aquí está la idea:
- Leer un
std::string
del flujo de entrada (std::ifstream
), cada instancia leída será la ruta completa - hacer un
find_last_of
en la cuerda para el\
- Extraiga una subcadena desde esta posición hasta el final, esto ahora le dará el nombre del archivo
- hacer un
find_last_of
por.
y una subcadena a cada lado le dará nombre + extensión.
-
Y -1 por no ser portátil 🙂
– Cos
13 de diciembre de 2010 a las 16:12
-
¿Por qué el voto negativo? Si hay algo mal con lo que dije, ¡avísame y lo arreglaré!
– Nim
13 de diciembre de 2010 a las 16:13
-
@Kos, bueno, ¡eso es duro! coincide con lo que quiere el OP, el archivo está basado en Windows y no había ningún requisito de portabilidad.
– Nim
13 de diciembre de 2010 a las 16:14
-
Como mínimo, una ruta válida de Windows puede tener los directorios separados por
/
también. Y ni siquiera sé si existen más advertencias en las especificaciones de la ruta, por lo que mi pensamiento es simple: si hay una buena biblioteca que hace lo que quiero, debería usarla, porque probablemente logrará mi objetivo mejor que yo. 😉– Cos
13 de diciembre de 2010 a las 16:17
-
@Nim, pero ¿no hay un
boost::insects::disperser<T>
plantilla genérica para eso? 🙂– Cos
13 de diciembre de 2010 a las 17:28
El siguiente truco para extraer el nombre del archivo de una ruta de archivo sin extensión en C++ (no se requieren bibliotecas externas):
#include <iostream>
#include <string>
using std::string;
string getFileName(const string& s) {
char sep = "https://stackoverflow.com/";
#ifdef _WIN32
sep = '\\';
#endif
size_t i = s.rfind(sep, s.length());
if (i != string::npos)
{
string filename = s.substr(i+1, s.length() - i);
size_t lastindex = filename.find_last_of(".");
string rawname = filename.substr(0, lastindex);
return(rawname);
}
return("");
}
int main(int argc, char** argv) {
string path = "/home/aymen/hello_world.cpp";
string ss = getFileName(path);
std::cout << "The file name is \"" << ss << "\"\n";
}
-
Y -1 por no ser portátil 🙂
– Cos
13 de diciembre de 2010 a las 16:12
-
¿Por qué el voto negativo? Si hay algo mal con lo que dije, ¡avísame y lo arreglaré!
– Nim
13 de diciembre de 2010 a las 16:13
-
@Kos, bueno, ¡eso es duro! coincide con lo que quiere el OP, el archivo está basado en Windows y no había ningún requisito de portabilidad.
– Nim
13 de diciembre de 2010 a las 16:14
-
Como mínimo, una ruta válida de Windows puede tener los directorios separados por
/
también. Y ni siquiera sé si existen más advertencias en las especificaciones de la ruta, por lo que mi pensamiento es simple: si hay una buena biblioteca que hace lo que quiero, debería usarla, porque probablemente logrará mi objetivo mejor que yo. 😉– Cos
13 de diciembre de 2010 a las 16:17
-
@Nim, pero ¿no hay un
boost::insects::disperser<T>
plantilla genérica para eso? 🙂– Cos
13 de diciembre de 2010 a las 17:28
svanschalkwyk
También uso este fragmento de código para determinar el carácter de barra inclinada apropiado:
boost::filesystem::path slash("https://stackoverflow.com/");
boost::filesystem::path::string_type preferredSlash = slash.make_preferred().native();
y luego reemplace las barras con la barra inclinada preferida para el sistema operativo. Útil si uno está implementando constantemente entre Linux/Windows.