I tested it on Linux, and on Windows, and on OS X: on every platform,
near as I can tell, it's substantially faster to read resources directly from the jar file rather than unpacking them first. Why would that be? Well, for starters, I'm guessing it takes less time to decompress data than to read more data from the storage device. Also, it's likely to use disk space more efficiently: having all the resources in one jar makes it more likely that they'll occupy adjacent blocks, not to mention the fact that there's less wasted space from partially filled blocks. So, add an option to avoid unpacking files from jars before reading them. This doesn't work with FastImageIO's memory-mapped image reading, but we don't use that in Spiral Knights. git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@1164 ed5b42cb-e716-0410-a449-f6a68f950b19
This commit is contained in:
@@ -60,12 +60,31 @@ public class FileResourceBundle extends ResourceBundle
|
||||
* @param source a file object that references our source jar file.
|
||||
* @param delay if true, the bundle will wait until someone calls {@link #sourceIsReady}
|
||||
* before allowing access to its resources.
|
||||
* @param unpack if true the bundle will unpack itself into a temporary directory
|
||||
* @param unpackFully if true the bundle will unpack itself fully.
|
||||
*/
|
||||
public FileResourceBundle (File source, boolean delay, boolean unpack)
|
||||
public FileResourceBundle (File source, boolean delay, boolean unpackFully)
|
||||
{
|
||||
this(source, delay, unpackFully, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a resource bundle with the supplied jar file.
|
||||
*
|
||||
* @param source a file object that references our source jar file.
|
||||
* @param delay if true, the bundle will wait until someone calls {@link #sourceIsReady}
|
||||
* before allowing access to its resources.
|
||||
* @param unpackFully if true the bundle will unpack itself fully.
|
||||
* @param unpackEntries if true and unpackFully is false, individual entries will be
|
||||
* unpacked into a temporary directory as needed (as opposed to being read directly from
|
||||
* the jar file).
|
||||
*/
|
||||
public FileResourceBundle (
|
||||
File source, boolean delay, boolean unpackFully, boolean unpackEntries)
|
||||
{
|
||||
_source = source;
|
||||
if (unpack) {
|
||||
_unpackEntries = unpackEntries;
|
||||
|
||||
if (unpackFully) {
|
||||
String root = stripSuffix(source.getPath());
|
||||
_unpacked = new File(root + ".stamp");
|
||||
_cache = new File(root);
|
||||
@@ -86,17 +105,25 @@ public class FileResourceBundle extends ResourceBundle
|
||||
public InputStream getResource (String path)
|
||||
throws IOException
|
||||
{
|
||||
// unpack our resources into a temp directory so that we can load
|
||||
// them quickly and the file system can cache them sensibly
|
||||
File rfile = getResourceFile(path);
|
||||
return (rfile == null) ? null : new FileInputStream(rfile);
|
||||
// if specified, unpack our resources into a temp directory so that
|
||||
// we can load them quickly and the file system can cache them sensibly
|
||||
if (_unpackEntries) {
|
||||
File rfile = getResourceFile(path);
|
||||
return (rfile == null) ? null : new FileInputStream(rfile);
|
||||
}
|
||||
if (_jarSource == null && resolveJarFile()) {
|
||||
return null;
|
||||
}
|
||||
JarEntry entry = _jarSource.getJarEntry(path);
|
||||
return (entry == null) ? null : _jarSource.getInputStream(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BufferedImage getImageResource (String path, boolean useFastIO)
|
||||
throws IOException
|
||||
{
|
||||
return ResourceManager.loadImage(getResourceFile(path), useFastIO);
|
||||
return _unpackEntries ? ResourceManager.loadImage(getResourceFile(path), useFastIO) :
|
||||
ResourceManager.loadImage(getResource(path), useFastIO);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,6 +427,9 @@ public class FileResourceBundle extends ResourceBundle
|
||||
/** The jar file from which we load resources. */
|
||||
protected JarFile _jarSource;
|
||||
|
||||
/** Whether or not to unpack individual entries as needed from the jar file. */
|
||||
protected boolean _unpackEntries;
|
||||
|
||||
/** A directory in which we temporarily unpack our resource files. */
|
||||
protected static File _tmpdir;
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ public class ResourceManager
|
||||
// check a system property to determine if we should unpack our bundles, but don't freak
|
||||
// out if we fail to read it
|
||||
try {
|
||||
_unpack = !Boolean.getBoolean("no_unpack_resources");
|
||||
_unpackFully = !Boolean.getBoolean("no_unpack_resources");
|
||||
} catch (SecurityException se) {
|
||||
// no problem, we're in a sandbox so we definitely won't be unpacking
|
||||
}
|
||||
@@ -263,7 +263,16 @@ public class ResourceManager
|
||||
*/
|
||||
public void setUnpackResources (boolean unpackResources)
|
||||
{
|
||||
_unpack = unpackResources;
|
||||
_unpackFully = unpackResources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether we unpack individual jar entries as opposed to reading them directly from
|
||||
* the jar.
|
||||
*/
|
||||
public void setUnpackEntries (boolean unpackEntries)
|
||||
{
|
||||
_unpackEntries = unpackEntries;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -440,7 +449,8 @@ public class ResourceManager
|
||||
public boolean checkBundle (String path)
|
||||
{
|
||||
File bfile = getResourceFile(path);
|
||||
return (bfile == null) ? false : new FileResourceBundle(bfile, true, _unpack).isUnpacked();
|
||||
return (bfile == null) ? false : new FileResourceBundle(
|
||||
bfile, true, _unpackFully, _unpackEntries).isUnpacked();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -459,7 +469,8 @@ public class ResourceManager
|
||||
return;
|
||||
}
|
||||
|
||||
final FileResourceBundle bundle = new FileResourceBundle(bfile, true, _unpack);
|
||||
final FileResourceBundle bundle = new FileResourceBundle(
|
||||
bfile, true, _unpackFully, _unpackEntries);
|
||||
if (bundle.isUnpacked()) {
|
||||
if (bundle.sourceIsReady()) {
|
||||
listener.requestCompleted(bundle);
|
||||
@@ -812,7 +823,8 @@ public class ResourceManager
|
||||
{
|
||||
if (setType.equals(FILE_SET_TYPE)) {
|
||||
FileResourceBundle bundle =
|
||||
createFileResourceBundle(getResourceFile(path), true, _unpack);
|
||||
createFileResourceBundle(getResourceFile(path),
|
||||
true, _unpackFully, _unpackEntries);
|
||||
if (!bundle.isUnpacked() || !bundle.sourceIsReady()) {
|
||||
dlist.add(bundle);
|
||||
}
|
||||
@@ -828,9 +840,9 @@ public class ResourceManager
|
||||
* Creates an appropriate bundle for fetching resources from files.
|
||||
*/
|
||||
protected FileResourceBundle createFileResourceBundle (File source, boolean delay,
|
||||
boolean unpack)
|
||||
boolean unpackFully, boolean unpackEntries)
|
||||
{
|
||||
return new FileResourceBundle(source, delay, unpack);
|
||||
return new FileResourceBundle(source, delay, unpackFully, unpackEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1066,8 +1078,11 @@ public class ResourceManager
|
||||
/** The root path we give to network bundles for all resources they're interested in. */
|
||||
protected String _networkRootPath;
|
||||
|
||||
/** Whether or not to unpack our resource bundles. */
|
||||
protected boolean _unpack;
|
||||
/** Whether or not to unpack our resource bundles fully. */
|
||||
protected boolean _unpackFully;
|
||||
|
||||
/** Whether or not to unpack individual jar entries. */
|
||||
protected boolean _unpackEntries = true;
|
||||
|
||||
/** Our default resource set. */
|
||||
protected ResourceBundle[] _default = new ResourceBundle[0];
|
||||
|
||||
Reference in New Issue
Block a user