From ed2526ec9513f14e68ab7e452964e24ea1d09917 Mon Sep 17 00:00:00 2001 From: Robert von Burg Date: Sun, 12 May 2019 20:18:01 +0200 Subject: [PATCH] [Fix] first write files to a temporary path, then rename to actual path this solves issues where files are not written properly on power failure. --- .../java/li/strolch/xmlpers/api/FileIo.java | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileIo.java b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileIo.java index fa024059c..1378b3b14 100644 --- a/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileIo.java +++ b/li.strolch.xmlpers/src/main/java/li/strolch/xmlpers/api/FileIo.java @@ -50,16 +50,18 @@ public class FileIo { private static final Logger logger = LoggerFactory.getLogger(FileIo.class); private final File path; + private final File tmpPath; public FileIo(File path) { this.path = path; + this.tmpPath = new File(this.path.getParentFile(), ".tmp_" + this.path.getName()); } public void writeSax(PersistenceContext ctx) { - XMLStreamWriter writer = null; + XMLStreamWriter writer; try { - try (FileWriter fileWriter = new FileWriter(this.path);) { + try (FileWriter fileWriter = new FileWriter(this.tmpPath)) { XMLOutputFactory factory = XMLOutputFactory.newInstance(); writer = factory.createXMLStreamWriter(fileWriter); @@ -78,9 +80,16 @@ public class FileIo { writer.flush(); } + if (!this.tmpPath.renameTo(this.path)) { + throw new IllegalStateException( + "Failed to rename temp file " + this.tmpPath.getName() + " to " + this.path.getAbsolutePath()); + } + } catch (FactoryConfigurationError | XMLStreamException | IOException e) { - if (this.path.exists()) - this.path.delete(); + if (this.tmpPath.exists()) { + if (!this.tmpPath.delete()) + logger.error("Failed to delete existing temp file " + this.tmpPath.getAbsolutePath()); + } String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, e.getMessage()); throw new XmlException(msg, e); @@ -149,20 +158,25 @@ public class FileIo { // transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", "\t"); // Transform to file - StreamResult result = new StreamResult(this.path); + StreamResult result = new StreamResult(this.tmpPath); Source xmlSource = new DOMSource(document); transformer.transform(xmlSource, result); if (logger.isDebugEnabled()) { - String msg = MessageFormat.format("Wrote DOM to {0}", this.path.getAbsolutePath()); //$NON-NLS-1$ + String msg = MessageFormat.format("Wrote DOM to {0}", this.tmpPath.getAbsolutePath()); //$NON-NLS-1$ logger.info(msg); } + if (!this.tmpPath.renameTo(this.path)) { + throw new IllegalStateException( + "Failed to rename temp file " + this.tmpPath.getName() + " to " + this.path.getAbsolutePath()); + } + } catch (TransformerFactoryConfigurationError | TransformerException e) { - - if (this.path.exists()) - this.path.delete(); - + if (this.tmpPath.exists()) { + if (!this.tmpPath.delete()) + logger.error("Failed to delete existing temp file " + this.tmpPath.getAbsolutePath()); + } String msg = "Writing to file failed due to internal error: {0}"; //$NON-NLS-1$ msg = MessageFormat.format(msg, e.getMessage()); throw new XmlException(msg, e);