diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java index c8b174c2..a854d19f 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/control/WorldBuilder.java @@ -21,6 +21,7 @@ import codemetropolis.toolchain.rendering.exceptions.TooLongRenderDurationException; import codemetropolis.toolchain.rendering.model.building.*; import codemetropolis.toolchain.rendering.model.primitive.Boxel; +import codemetropolis.toolchain.rendering.util.BlockCsvWriterHolder; public class WorldBuilder { @@ -98,6 +99,9 @@ public void createBlocks(File directory, int maxTime) throws TooLongRenderDurati raiseProgressEvent(BuildPhase.GENERATING_BLOCKS, count, total, timeElapsed); } stopWatch.stop(); + + // Close all PrintWriters after every single block has been written + BlockCsvWriterHolder.closeWriters(); } public void build(File sourceDirectory) throws RenderingException { diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java index 931fff2c..84cb7acd 100644 --- a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/model/primitive/Boxel.java @@ -1,15 +1,13 @@ package codemetropolis.toolchain.rendering.model.primitive; -import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; -import java.io.FileWriter; -import java.io.IOException; import java.io.PrintWriter; import codemetropolis.blockmodifier.World; import codemetropolis.toolchain.commons.cmxml.Point; import codemetropolis.toolchain.rendering.model.BasicBlock; +import codemetropolis.toolchain.rendering.util.BlockCsvWriterHolder; public class Boxel implements Primitive { @@ -71,17 +69,14 @@ public int toCSVFile(File directory) { int x = position.getX() >> 9; int z = position.getZ() >> 9; - directory.mkdirs(); String filename = String.format("blocks.%d.%d.csv", x, z); - File file = new File(directory, filename); - try(PrintWriter writer = new PrintWriter(new BufferedWriter(new FileWriter(file, true)))) { + try { + PrintWriter writer = BlockCsvWriterHolder.requestFile(directory, filename); String csv = toCSV(); if(csv != null) writer.println(csv); } catch (FileNotFoundException e) { e.printStackTrace(); - } catch (IOException e1) { - e1.printStackTrace(); } return 1; } diff --git a/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/util/BlockCsvWriterHolder.java b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/util/BlockCsvWriterHolder.java new file mode 100644 index 00000000..7c2f9c3e --- /dev/null +++ b/sources/codemetropolis-toolchain-rendering/src/main/java/codemetropolis/toolchain/rendering/util/BlockCsvWriterHolder.java @@ -0,0 +1,66 @@ +package codemetropolis.toolchain.rendering.util; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Map; + +/** + * This class is used to hold PrintWriter instances for the rendering. Previously, these files were (re-)opened and + * closed for every single {@link codemetropolis.toolchain.rendering.model.primitive.Boxel}. Instead of that, it now + * holds all of the references for each file, and serves them to the Boxel for writing. When all Boxels have been + * written, all these files can be flushed and closed at once. + * + * @author Adam Bankeszi {@literal } {@literal } + */ +public class BlockCsvWriterHolder { + + /** Holds the PrintWriter references for the blocks csv files. */ + private static Map writers = new HashMap(); + + /** + * Requests a {@link PrintWriter} for the given filename. On the first request it attempts to create the file and + * stores the associated {@link PrintWriter} reference. When the same file is requested a second time, it simply + * returns the already open {@link PrintWriter}. + * + * @param directory The directory in which these files shall be stored. + * @param filename The requested file's name. + * @return The {@link PrintWriter} for the requested file. + * @throws FileNotFoundException if it fails to create the file (or the parent directory). See + * {@link #createAndStoreWriter(File, String)} for more information. + */ + public static PrintWriter requestFile(File directory, String filename) throws FileNotFoundException { + if (writers.containsKey(filename)) { + return writers.get(filename); + } else { + return createAndStoreWriter(directory, filename); + } + } + + /** + * Closes all {@link PrintWriter} instances and clears the storage. + */ + public static void closeWriters() { + writers.values().forEach(writer -> writer.close()); + writers.clear(); + } + + /** + * Creates a new {@link PrintWriter} instance for the specific filename and adds it to the storage. + * + * @param directory The directory in which the file should be created. + * @param filename The filename that should be used. + * @return The new {@link PrintWriter} instance for the newly created file. + * @throws FileNotFoundException if it fails to create the file (or the parent directory). Its most likely due to + * insufficent user permissions for the given path or insufficent drive space. + */ + private static PrintWriter createAndStoreWriter(File directory, String filename) throws FileNotFoundException { + directory.mkdirs(); + File file = new File(directory, filename); + PrintWriter writer = new PrintWriter(file); + writers.put(filename, writer); + return writer; + } + +}