I was wondering how to use JavaScript to do async zip writing and reading.
可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
回答1:
Here is an example for zip reading using nsIZipReader, zip writing goes in a similar way. The example reads a zip file from /tmp/example.zip
and prints the content of the first file to the console.
Remarks:
- I'm using
nsIInputStreamPump
for async I/O I found a reference to this API at the Streams guide on MDN. This interface offers a.asyncRead
method which takes an object that implementsnsIStreamListener
(andnsIRequestObserver
). - I have compared the running time of this example with the synchronous zip reading example at MDN and found that reading the time used by the blocking read is significantly smaller (reading a zip file from RAM disk: from 1-2ms to 0.1-0.3ms) (measured using
console.time('foo');
before thereusableStreamInstance.init
invocation andconsole.timeEnd('foo');
afterreusableStreamInstance.readBytes
). - I am using
.readBytes
instead of.read
to avoid truncation of data if the file contains a null byte. - I haven't implemented any error handling (zip not existent, zip doesn't contain a file, zip/file cannot be opened), but I do close the zipreader regardless of whether an error occurs.
let { Cc: classes, Cu: utils, Ci: interfaces } = Components;
Cu.import('resource://gre/modules/FileUtils.jsm');
let pathToZip = '/tmp/example.zip';
let nsiFileZip = new FileUtils.File(pathToZip);
let streamListener = {
buffer: null,
// nsIRequestObserver
onStartRequest: function(aRequest, aContext) {
this.buffer = [];
},
// nsIStreamListener
onDataAvailable:
function(aRequest, aContext, aInputStream, aOffset, aCount) {
let reusableStreamInstance = Cc['@mozilla.org/scriptableinputstream;1']
.createInstance(Ci.nsIScriptableInputStream);
reusableStreamInstance.init(aInputStream);
let chunk = reusableStreamInstance.readBytes(aCount);
this.buffer.push(chunk);
},
// nsIRequestObserver
onStopRequest: function(aRequest, aContext, aStatusCode) {
console.log('end', aStatusCode);
var data = this.buffer.join('');
console.log(data);
}
};
let pump = Cc['@mozilla.org/network/input-stream-pump;1']
.createInstance(Ci.nsIInputStreamPump);
let zr = Cc['@mozilla.org/libjar/zip-reader;1']
.createInstance(Ci.nsIZipReader);
try {
zr.open(nsiFileZip);
// null = no entry name filter.
var entries = zr.findEntries(null);
while (entries.hasMore()) {
var entryPointer = entries.getNext();
var entry = zr.getEntry(entryPointer);
if (!entry.isDirectory) {
var stream = zr.getInputStream(entryPointer);
pump.init(stream, 0, -1, 0, 0, true);
pump.asyncRead(streamListener, null);
// For the demo, we only take one file, so break now.
break;
}
}
} finally {
zr.close();
}