Para renombrar un archivo en C++ se usa std::filesystem::rename, de C++17. La misma función sirve para moverlo a otra carpeta. Lo importante es cómo te enteras de que algo salió mal, qué pasa si el nombre nuevo ya existe y por qué falla al mover entre discos.
También te puede interesar
Los ejemplos trabajan dentro de una carpeta salida con tres archivos, informe.txt, notas.txt y viejo.txt, y una subcarpeta archivo. Cada programa la prepara al empezar con una función que no mostramos, para que dé siempre el mismo resultado.
Renombrar con std::filesystem::rename
#include <filesystem>
#include <print>
namespace fs = std::filesystem;
int main()
{
fs::rename("salida/informe.txt", "salida/informe-2026.txt");
std::println("existe el viejo: {}", fs::exists("salida/informe.txt"));
std::println("existe el nuevo: {}", fs::exists("salida/informe-2026.txt"));
}salidaexiste el viejo: false existe el nuevo: true
std::filesystem::rename llegó con C++17 y funciona igual con archivos y con carpetas. Si algo falla, lanza std::filesystem::filesystem_error, y el mensaje trae las dos rutas:
#include <filesystem>
#include <print>
namespace fs = std::filesystem;
int main()
{
try {
fs::rename("salida/no-existe.txt", "salida/otro.txt");
} catch (const fs::filesystem_error& e) {
std::println("{}", e.what());
std::println("ruta 1: {}", e.path1().string());
}
}salidafilesystem error: cannot rename: No such file or directory [salida/no-existe.txt] [salida/otro.txt] ruta 1: salida/no-existe.txt
Sin excepciones: std::error_code
#include <filesystem>
#include <print>
namespace fs = std::filesystem;
int main()
{
std::error_code ec;
fs::rename("salida/no-existe.txt", "salida/otro.txt", ec);
if (ec) {
std::println("no se pudo: {} (código {})", ec.message(), ec.value());
}
}salidano se pudo: No such file or directory (código 2)
Todas las funciones de std::filesystem tienen una versión que, en lugar de lanzar, deja el error en un std::error_code. Es la cómoda cuando que algo falle es normal, por ejemplo al procesar muchos archivos y querer seguir con el resto.
Si el nombre nuevo ya existe, se pisa sin preguntar
#include <filesystem>
#include <print>
#include <string>
namespace fs = std::filesystem;
int main()
{
fs::rename("salida/viejo.txt", "salida/notas.txt");
std::ifstream f("salida/notas.txt");
std::string contenido;
std::getline(f, contenido);
std::println("notas.txt ahora contiene: {}", contenido);
}salidanotas.txt ahora contiene: notas viejas
En Linux y macOS, renombrar encima de un archivo existente lo sustituye sin avisar: las «notas nuevas» se han perdido. En Windows, el comportamiento depende de la función y de la versión del compilador, así que no conviene contar con él. Si no quieres pisar nada, comprueba antes:
#include <filesystem>
#include <print>
namespace fs = std::filesystem;
int main()
{
auto renombrar_sin_pisar = [](const fs::path& de, const fs::path& a) {
if (fs::exists(a)) {
std::println("{} ya existe: no se renombra", a.string());
return false;
}
fs::rename(de, a);
return true;
};
renombrar_sin_pisar("salida/viejo.txt", "salida/notas.txt");
renombrar_sin_pisar("salida/viejo.txt", "salida/notas-viejas.txt");
std::println("existe notas-viejas.txt: {}", fs::exists("salida/notas-viejas.txt"));
}salidasalida/notas.txt ya existe: no se renombra existe notas-viejas.txt: true
Ojo: entre el exists y el rename otro programa podría crear el destino. Para un script personal da igual; en un servidor donde varios procesos tocan la misma carpeta, hay que usar mecanismos del sistema operativo (en Linux, renameat2 con RENAME_NOREPLACE).
Mover a otra carpeta
Mover y renombrar son la misma operación: basta con que la ruta nueva esté en otra carpeta.
#include <filesystem>
#include <print>
namespace fs = std::filesystem;
int main()
{
fs::rename("salida/informe.txt", "salida/archivo/informe.txt");
for (const auto& e : fs::directory_iterator("salida/archivo")) {
std::println("en archivo/: {}", e.path().filename().string());
}
}salidaen archivo/: informe.txt
Pero solo si las dos rutas están en el mismo sistema de archivos. Entre discos distintos, o entre una carpeta compartida y otra del sistema, rename falla. En el contenedor donde probamos estos ejemplos, la carpeta de trabajo y /tmp están en sistemas de archivos distintos, así que se ve el error real:
#include <filesystem>
#include <print>
namespace fs = std::filesystem;
int main()
{
std::error_code ec;
fs::rename("salida/informe.txt", "/tmp/informe.txt", ec);
std::println("rename: {}", ec ? ec.message() : "bien");
if (ec == std::errc::cross_device_link) {
fs::copy_file("salida/informe.txt", "/tmp/informe.txt", fs::copy_options::overwrite_existing);
fs::remove("salida/informe.txt");
std::println("copiado y borrado el original: {}", fs::exists("/tmp/informe.txt"));
}
}salidarename: Invalid cross-device link copiado y borrado el original: true
El remedio es lo que hacen el Explorador de Windows o la orden mv: copiar y, cuando la copia está completa, borrar el original.
Cambiar la extensión de varios archivos
#include <filesystem>
#include <print>
#include <algorithm>
#include <string>
#include <vector>
namespace fs = std::filesystem;
int main()
{
for (const auto& e : fs::directory_iterator("salida")) {
if (e.is_regular_file() && e.path().extension() == ".txt") {
fs::path nuevo = e.path();
nuevo.replace_extension(".md");
fs::rename(e.path(), nuevo);
}
}
std::vector<std::string> nombres;
for (const auto& e : fs::directory_iterator("salida")) {
nombres.push_back(e.path().filename().string());
}
std::ranges::sort(nombres); // el orden del directorio no está garantizado
std::println("{}", nombres);
}salida["archivo", "informe.md", "notas.md", "viejo.md"]
directory_iterator devuelve los archivos en el orden en que los guarda el sistema, que no es alfabético: si el resultado tiene que salir ordenado, ordénalo tú. Hay más sobre recorrer carpetas en Carpetas y archivos con std::filesystem.
La función de C: std::rename
#include <filesystem>
#include <print>
#include <cstdio>
namespace fs = std::filesystem;
int main()
{
if (std::rename("salida/no-existe.txt", "salida/otro.txt") != 0) {
std::perror("std::rename");
}
}salidastd::rename: No such file or directory
Es la que usaba la versión anterior de esta página y sigue funcionando en cualquier compilador de C o de C++: devuelve 0 si fue bien y otra cosa si no, y perror imprime el motivo. La de std::filesystem es preferible porque trabaja con fs::path y da errores más claros.
Todo el código de esta página se compiló con GCC 15.3 (C++23, -std=c++23 -Wall -Wextra, sin avisos) y se ejecutó en Linux, en un contenedor limpio sin acceso a la red, antes de publicarla; las salidas están copiadas de esa ejecución.