En el desarrollo con Rust, la manipulación de rutas y nombres de archivo requiere un manejo cuidadoso de las cadenas de texto nativas del sistema operativo. Las estructuras OsString y &OsStr están diseñadas específicamente para representar estas cadenas de manera agnóstica a la plataforma.
- En entornos Unix, estas cadenas se almacenan como secuencias de valores de 8 bits distintos de cero, compatibles con la codificación UTF-8.
- En sistemas Windows, se almacenan como secuencias de valores de 16 bits distintos de cero, utilizando la codificación UTF-16.
Al implementar funcionalidades como la generación de copias de seguridad o la carga de archivos adjuntos, es común necesitar ensamblar nombres de archivo de forma dinámica. A continuación, se muestra cómo lograr esto utilizando operaciones de concatenación sobre arreglos.
Enasmblaje Dinámico de Nombres de Archivo
#[cfg(test)]
mod tests {
use std::ffi::{OsStr, OsString};
#[test]
fn construir_nombre_archivo_dinamico() {
let parte_id = OsStr::new("doc");
let parte_fecha = OsStr::new("_20231027");
let parte_usuario = OsStr::new("_admin");
let extension = OsStr::new(".pdf");
let componentes = [parte_id, parte_fecha, parte_usuario, extension];
let nombre_final: OsString = componentes.join(OsStr::new(""));
assert_eq!(nombre_final, OsStr::new("doc_20231027_admin.pdf"));
}
}
Análisis y Manipulación de Rutas en Windows
En entornos Windows, a menudo es necesario extraer información específica de un nombre de archivo y reestructurarlo. Esto implica trabajar directamente con la codiifcación UTF-16 subyacente mediante las extensiones del sistema operativo.
#[cfg(test)]
#[cfg(windows)]
mod windows_tests {
use std::ffi::{OsStr, OsString};
use std::os::windows::ffi::{OsStrExt, OsStringExt};
#[test]
fn procesar_y_dividir_nombre_en_windows() {
// Conversión a secuencia UTF-16
let nombre_base = OsStr::new("reporte_final");
let codificacion_utf16: Vec<u16> = nombre_base.encode_wide().collect();
// Verificación de la codificación UTF-16
let esperado_utf16: Vec<u16> = "reporte_final".encode_utf16().collect();
assert_eq!(codificacion_utf16, esperado_utf16);
// División utilizando split_off para separar y mutar el vector original
let mut utf16_mutable: Vec<u16> = nombre_base.encode_wide().collect();
let parte_derecha = utf16_mutable.split_off(7);
assert_eq!(utf16_mutable, "reporte".encode_utf16().collect::<vec>>());
assert_eq!(parte_derecha, "_final".encode_utf16().collect::<vec>>());
// División utilizando split_at para obtener vistas inmutables
let bytes_completos: Vec<u16> = nombre_base.encode_wide().collect();
let (prefijo, sufijo) = bytes_completos.split_at(7);
assert_eq!(prefijo, "reporte".encode_utf16().collect::<vec>>().as_slice());
assert_eq!(sufijo, "_final".encode_utf16().collect::<vec>>().as_slice());
// Uso de splitn para dividir por un delimitador específico (ej. guion bajo)
let nombre_complejo = OsStr::new("logs_servidor_2023_octubre");
let bytes_utf16: Vec<u16> = nombre_complejo.encode_wide().collect();
let segmentos: Vec<&[u16]> = bytes_utf16
.splitn(4, |&codigo| codigo == '_' as u16)
.collect();
assert_eq!(segmentos.len(), 4);
// Reconstrucción de una sección específica (ej. el año) a OsString
let anio_os_string = OsString::from_wide(segmentos[2]);
assert_eq!(anio_os_string.into_string().unwrap(), "2023");
}
}
</u16></vec></vec></u16></vec></vec></u16></u16></u16>