Estoy ejecutando una operación de ejecución prolongada, digamos 100k trabajos. Quiero actualizar el progreso en un archivo una vez que se completen cada 100 trabajos de este tipo.
estoy abriendo el archivo usando bufferedWriter con el modo de adición como falso. Escribiéndolo y luego cerrándolo. esto se hace una vez que se completan 100 trabajos. Entonces, el archivo abierto y cerrado habría sucedido 1000 veces. ¿Puedo optimizarlo aún más abriendo y cerrando el archivo solo una vez?
public static void writeMetaData(String writeDir, JSONObject jsonObject) throws Exception { String filePath = writeDir.concat("/").concat("metadata.txt"); BufferedWriter metaDataWriter = Files.newBufferedWriter(Paths.get(filePath), StandardCharsets.UTF_8, StandardOpenOption.TRUNCATE_EXISTING); metaDataWriter.write(jsonObject.toString()); IOUtils.closeQuietly(metaDataWriter); } for(int i =0 ; i < 100000; i++) { // do Something; if(i % 100 == 0) { writeMetaData(writeDir, jsonObject); } }El archivo solo debe tener una sola línea.
Contenido de archivo esperado después de 100 trabajos: progress: 100 Contenido de archivo esperado después de 200 trabajos: progress: 200
¿Se puede optimizar más?
Un Stream no permite volver atrás y reescribir el contenido. Una forma de lograr lo que quieres es usar un RandomAccessFile . Su método setLength() truncará el archivo si pasa 0 .
Aquí hay un ejemplo simple:
import java.io.*; public class Test { public static void updateFile(RandomAccessFile raf, String content) throws IOException { raf.setLength(0); raf.write(content.getBytes("UTF-8")); } public static void main(String[] args) throws IOException { try(RandomAccessFile raf = new RandomAccessFile("metadata.txt", "rw")) { updateFile(raf, "progress: 100"); updateFile(raf, "progress: 200"); } } }Las operaciones de archivo generalmente están almacenadas en el kernel subyacente, por lo que es poco probable que vea un gran beneficio en el rendimiento al mantener un descriptor de archivo abierto para este tipo de aplicación de bajo rendimiento.
Mantener su código como una sola operación que no deja ningún estado después de que finaliza, en lugar de diseñarlo como un flujo rebobinable continuo, lo convierte en una implementación elegante, simple y, a menos que haya solicitado específicamente IO síncrono, también lo suficientemente eficaz que se beneficia de las optimizaciones de todas las capas que se encuentran debajo de él.
Cuando obtenga una impedancia medible para el rendimiento con esto, lo que sospecho que nunca lo hará, podría usar la API RandomAccessFile o ir innecesariamente a un nivel más bajo usando FileChannel como otros ya han especificado.
Creo que no debería comprometer la simplicidad/elegancia de su diseño para este tipo de microoptimización, que en el gran esquema de las cosas, está garantizado que será insignificante (una pequeña operación de escritura por cada 100 trabajos procesados).