/** * Loop through the ZIP file, copying its entries into a new, temporary ZIP file, skipping the * entry to be deleted. Then replace the original file with the new one. */ protected Integer deleteEntry() throws XMLDataStoreException { try { ZipInputStream inStream = this.buildZipInputStream(); File outFile = this.buildTempFile(); ZipOutputStream outStream = new ZipOutputStream(new FileOutputStream(outFile)); byte[] buffer = new byte[32768]; int inCount = 0; int outCount = 0; // copy all the entries except the one to be deleted ZipEntry entry = inStream.getNextEntry(); while (entry != null) { inCount++; if (!this.getZipEntryName().equals(entry.getName())) { outCount++; outStream.putNextEntry(entry); int byteCount; while ((byteCount = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, byteCount); } outStream.closeEntry(); } entry = inStream.getNextEntry(); } inStream.close(); if (outCount == 0) { // add a dummy record to an empty file so we can close it // this is required by ZipOutputStream outStream.putNextEntry(new ZipEntry("delete.txt")); outStream.write( "This file is a place-holder. The containing ZIP file should be deleted.".getBytes()); outStream.closeEntry(); } outStream.close(); if (outCount == inCount) { // no entries were removed - just delete the temp file outFile.delete(); } else { // at least one entry removed - delete the original file this.getFile().delete(); if (outCount == 0) { // NO entries remain - just delete the temp file too outFile.delete(); } else { // entries remain - replace original file with temp file outFile.renameTo(this.getFile()); } } return new Integer(inCount - outCount); // should be 0 or 1 } catch (IOException ex) { throw XMLDataStoreException.ioException(ex); } }
/** * Rename the ZIP file to a temporary file, then copy its entries back into the original ZIP file, * leaving the stream open and returning it. */ protected Writer buildWriteStream(boolean entryShouldExist) throws XMLDataStoreException { try { File inFile = this.buildTempFile(); inFile.delete(); // the file actually gets created - delete it boolean renameSucceeded = this.getFile().renameTo(inFile); ZipInputStream inStream = this.buildZipInputStream(inFile); ZipOutputStream outStream = this.buildZipOutputStream(); boolean entryActuallyExists = false; byte[] buffer = new byte[32768]; ZipEntry entry = inStream.getNextEntry(); while (entry != null) { boolean weWantToWriteTheEntry = true; if (this.getZipEntryName().equals(entry.getName())) { entryActuallyExists = true; // if we were expecting the entry, skip it; // if we were NOT expecting the entry, allow it to be rewritten // so the file is restored to its original condition if (entryShouldExist) { weWantToWriteTheEntry = false; } } if (weWantToWriteTheEntry) { outStream.putNextEntry(entry); int byteCount; while ((byteCount = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, byteCount); } outStream.closeEntry(); } entry = inStream.getNextEntry(); } // close and delete the temporary file inStream.close(); inFile.delete(); // check for invalid state if (entryShouldExist != entryActuallyExists) { outStream.close(); // close it since we will not be returning it // need more helpful exceptions here if (entryActuallyExists) { throw XMLDataStoreException.fileAlreadyExists(new File(this.getZipEntryName())); } else { throw XMLDataStoreException.fileNotFound(new File(this.getZipEntryName()), null); } } outStream.putNextEntry(new ZipEntry(this.getZipEntryName())); return new OutputStreamWriter(outStream); } catch (IOException ex) { throw XMLDataStoreException.ioException(ex); } }
/** * Build and return a temporary file in the same directory and with the same extension as the * specified file. */ protected File buildTempFile(File file) throws IOException { int i = file.getName().lastIndexOf('.'); String ext = ((i == -1) ? ".zip" : file.getName().substring(i)); File tempFile = File.createTempFile("temp", ext, file.getParentFile()); return tempFile; }