Escribir sin perder datos
El fallo más caro de una aplicación de escritorio: un fichero a medio escribir cuando se corta la luz. La escritura atómica, qué garantiza y qué no.
Qué pasa al escribir encima
Y no es un caso raro. En una aplicación que guarda automáticamente cada pocos minutos, la ventana de peligro se abre muchas veces al día durante años, en miles de máquinas.
El patrón
Escribir en otro sitio y luego sustituir de golpe:
pub fn escribir_atomico(destino: &Path, datos: &[u8]) -> std::io::Result<()> { let temporal = destino.with_extension("tmp"); // 1 · escribir entero en un fichero nuevo, en el mismo directorio let mut f = File::create(&temporal)?; f.write_all(datos)?; // 2 · forzar que llegue al disco de verdad, no solo a la memoria del sistema f.sync_all()?; // 3 · sustituir: reemplaza sin dejar un estado intermedio visible std::fs::rename(&temporal, destino)?; Ok(())}Los tres pasos son necesarios y el segundo es el que se olvida. Sin él, el sistema puede tener los datos en memoria y no en el disco cuando llegue el renombrado, con lo que un corte de luz deja un fichero nuevo vacío — que es el mismo desastre con más pasos.
Y el fichero temporal va en el mismo directorio que el destino, no en el de temporales del sistema: el renombrado solo es barato dentro del mismo sistema de ficheros. Entre directorios distintos puede convertirse en una copia, y entonces vuelve a haber ventana de peligro.
Qué garantiza y qué no
La tercera fila es la que marca el límite de esta lección y el motivo de los tres niveles siguientes: en cuanto lo que guardas tiene relaciones entre partes, los ficheros sueltos dejan de bastar.
Dónde hace falta
No en todo, y merece distinguir para no complicar el código por gusto:
- Sí: los datos del usuario, la configuración, cualquier cosa cuya pérdida sea un problema. Todo lo que el nivel 39.1 puso en «datos» y «configuración».
- No: cachés y temporales. Si se corrompen, se borran y se reconstruyen — que es su contrato del nivel 39.3.
- Y para los registros, tampoco: se escriben añadiendo al final, que no trunca nada, y una línea a medias en un registro es aceptable.