Цитата(Skipy @ 2.7.2010, 10:10 ) | Если мы читаем zip-файл из zip-файла, то чтобы вычитать содержимое внутреннего файла, даже структуру - надо спозиционироваться на директорию. А она лежит в конце файла. И чтобы вычислить точку, где она начинается (смещение известно) - надо распаковать весь внутренный файл и спозиционироваться в нем по этому смещению. Так что хочешь-не хочешь, а внутренний файл придется все-таки распаковать целиком. |
Это в теории. На практике же, если файл содержит только entries и central directory без лишних данных, вполне можно обойтись и без предварительного чтения central directory, можно просто сканировать поток на предмет entries и при желании сразу же их распаковывать. Код | package vingrad;
import org.apache.log4j.Logger;
import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream;
public class ZipStreamTest { private static final Logger logger = Logger.getLogger(ZipStreamTest.class);
public static void main(String[] args) { try { Logger earLogger = Logger.getLogger("ear"); InputStream ear = new LoggingInputStream(earLogger, new FileInputStream("C:\\TEMP\\EntAPI.ear")); ZipInputStream earZipInputStream = new ZipInputStream(ear); ZipEntry earEntry; while((earEntry = earZipInputStream.getNextEntry()) != null) { String name = earEntry.getName(); if(name.toLowerCase().endsWith(".war")) { Logger warLogger = Logger.getLogger("war"); InputStream war = new LoggingInputStream(warLogger, earZipInputStream); ZipInputStream warZipInputStream = new ZipInputStream(war); ZipEntry warEntry; while((warEntry = warZipInputStream.getNextEntry()) != null) { warLogger.info(" WAR: " + warEntry.getName()); } } } ear.close(); } catch(Exception e) { logger.error(e, e); } }
public static class LoggingInputStream extends InputStream { public static final int DEFAUL_BLOCK_SIZE = 1024;
private InputStream out; private int blockSize; private int written = 0; private final Logger logger;
public LoggingInputStream(Logger logger, InputStream in, int blockSize) { this.out = in; this.blockSize = blockSize; this.logger = logger; logger.info("Start reading"); }
public LoggingInputStream(Logger logger, InputStream in) { this(logger, in, DEFAUL_BLOCK_SIZE); }
private void increment(int amount) { int prevBlocks = written / blockSize; written += amount; int currentBlocks = written / blockSize; if(prevBlocks < currentBlocks && logger.isInfoEnabled()) { logger.info(String.format("Read %,10d bytes", written)); } }
public int read() throws IOException { int b = out.read(); increment(1); return b; }
public int read(byte[] b) throws IOException { int read = out.read(b); increment(read); return read; }
public int read(byte[] b, int off, int len) throws IOException { int read = out.read(b, off, len); increment(read); return read; }
public long skip(long n) throws IOException { long skipped = out.skip(n); increment((int) skipped); return skipped; }
public int available() throws IOException { return out.available(); }
public void close() throws IOException { out.close(); logger.info("Stop reading"); }
public void mark(int readlimit) { }
public void reset() throws IOException { }
public boolean markSupported() { return false; } } }
|
и по логам прекрасно видно, что последовательно читаются EAR файл, из него на лету извлекается WAR и читается его содержимое, без необходимости распаковывать до конца и читать central directoryКод | [INFO ] [ear] Start reading [INFO ] [war] Start reading [INFO ] [ear] Read 1 125 bytes [INFO ] [war] WAR: META-INF/ [INFO ] [war] WAR: META-INF/MANIFEST.MF [INFO ] [war] WAR: WEB-INF/ [INFO ] [war] WAR: WEB-INF/classes/ [INFO ] [war] WAR: WEB-INF/classes/config/ [INFO ] [war] WAR: WEB-INF/classes/config/SWSServiceLibrary/ [INFO ] [war] WAR: WEB-INF/lib/ [INFO ] [war] WAR: sws_services/ [INFO ] [war] WAR: WEB-INF/weblogic.xml [INFO ] [war] Read 1 218 bytes [INFO ] [war] WAR: WEB-INF/web.xml [INFO ] [ear] Read 2 149 bytes [INFO ] [war] Read 2 264 bytes [INFO ] [war] WAR: WEB-INF/classes/config/SWSServiceLibrary/SWS_Service.properties [INFO ] [war] WAR: WEB-INF/classes/config/SWSServiceLibrary/ServiceRegistryListResponse.xsd [INFO ] [ear] Read 3 173 bytes [INFO ] [war] WAR: WEB-INF/classes/config/SWSServiceLibrary/SWSInit.properties [INFO ] [war] WAR: WEB-INF/classes/config/SWSServiceLibrary/SWSServiceRequest.xsd [INFO ] [war] Read 3 122 bytes [INFO ] [war] WAR: WEB-INF/classes/config/SWSServiceLibrary/SWSServiceResponse.xsd [INFO ] [war] WAR: WEB-INF/classes/config/SWSFramework.properties [INFO ] [ear] Read 4 197 bytes [INFO ] [war] Read 4 168 bytes [INFO ] [war] WAR: WEB-INF/lib/gpfs-entitlement-impl-1.3.1.jar [INFO ] [ear] Read 5 221 bytes [INFO ] [war] Read 5 241 bytes [INFO ] [ear] Read 6 245 bytes [INFO ] [war] Read 6 264 bytes [INFO ] [ear] Read 7 269 bytes [INFO ] [war] Read 7 287 bytes [INFO ] [ear] Read 8 293 bytes [INFO ] [war] Read 8 309 bytes [INFO ] [ear] Read 9 317 bytes [INFO ] [war] Read 9 333 bytes [INFO ] [ear] Read 10 341 bytes [INFO ] [war] Read 10 356 bytes [INFO ] [ear] Read 11 365 bytes [INFO ] [war] Read 11 379 bytes [INFO ] [ear] Read 12 389 bytes [INFO ] [war] Read 12 404 bytes [INFO ] [ear] Read 13 413 bytes [INFO ] [war] Read 13 427 bytes [INFO ] [ear] Read 14 437 bytes <......>
|
--------------------
Disclaimer: this post contains explicit depictions of personal opinion. So, if it sounds sarcastic, don't take it seriously. If it sounds dangerous, do not try this at home or at all. And if it offends you, just don't read it.
|