Each .xz file consist of one or more Streams. Each Stream consist of zero or more Blocks. Each Stream contains an Index of Streams' Blocks. The Indexes from all Streams are loaded in RAM by a constructor of this class. A typical .xz file has only one Stream, and parsing its Index will need only three or four seeks.
To make random access possible, the data in a .xz file must be splitted into multiple Blocks of reasonable size. Decompression can only start at a Block boundary. When seeking to an uncompressed position that is not at a Block boundary, decompression starts at the beginning of the Block and throws away data until the target position is reached. Thus, smaller Blocks mean faster seeks to arbitrary uncompressed positions. On the other hand, smaller Blocks mean worse compression. So one has to make a compromise between random access speed and compression ratio.
Implementation Note
This class uses linear search to locate the correct Stream from the data structures in RAM. It was the simplest to implement and should be fine as long as there aren't too many Streams. The correct Block inside a Stream is located using binary search and thus is fast even with a huge number of Blocks.
The amount of memory needed for the Indexes is taken into account when checking the memory usage limit. Each Stream is calculated to need at least 1 KiB of memory and each Block 16 bytes of memory, rounded up to the next kibibyte. So unless the file has a huge number of Streams or Blocks, these don't take significant amount of memory.
When using XZOutputStream, a new Block can be started by calling
its endBlock method. If you know
that the decompressor will only need to seek to certain uncompressed
positions, it can be a good idea to start a new Block at (some of) these
positions (and only at these positions to get better compression ratio).
liblzma in XZ Utils supports starting a new Block with
LZMA_FULL_FLUSH. XZ Utils 5.1.1alpha added threaded
compression which creates multi-Block .xz files. XZ Utils 5.1.1alpha
also added the option --block-size=SIZE to the xz command
line tool. XZ Utils 5.1.2alpha added a partial implementation of
--block-list=SIZES which allows specifying sizes of
individual Blocks.
String filename = "foo.xz";
SeekableFileInputStream seekableFile
= new SeekableFileInputStream(filename);
try {
SeekableXZInputStream seekableXZ
= new SeekableXZInputStream(seekableFile);
System.out.println("Uncompressed size: " + seekableXZ.length());
} finally {
seekableFile.close();
}
SeekableFileInputStream, XZInputStream, XZOutputStream
| Modifier and Type | Field and Description |
|---|---|
| private final ArrayCache | arrayCache
Cache for big arrays. |
| private int | blockCount
Number of XZ Blocks in the file. |
| private BlockInputStream | blockDecoder
Decoder of the current XZ Block, if any. |
| private Check | check
Integrity Check in the current XZ Stream. |
| private int | checkTypes
Bitmask of all Check IDs seen. |
| private final BlockInfo | curBlockInfo
Size and position information about the current Block. |
| private long | curPos
Current uncompressed position. |
| private boolean | endReached
True when end of the file was reached. |
| private IOException | exception
Pending exception from an earlier error. |
| private SeekableInputStream | in
The input stream containing XZ compressed data. |
| private int | indexMemoryUsage
Memory usage of the IndexDecoders. |
| private long | largestBlockSize
Uncompressed size of the largest XZ Block in the file. |
| private final int | memoryLimit
Memory usage limit after the memory usage of the IndexDecoders have been substracted. |
| private final BlockInfo | queriedBlockInfo
Temporary (and cached) information about the Block whose information
is queried via |
| private boolean | seekNeeded
True when |
| private long | seekPos
Target position for seeking. |
| private final ArrayList | streams
List of IndexDecoders, one for each Stream in the file. |
| private final byte[] | tempBuf
Temporary buffer for read(). |
| private long | uncompressedSize
Uncompressed size of the file (all Streams). |
| private final boolean | verifyCheck
Flag indicating if the integrity checks will be verified. |
| Access | Constructor and Description |
|---|---|
| public | SeekableXZInputStream(SeekableInputStream
seekable input stream containing one or more
XZ Streams; the whole input stream is used in)Creates a new seekable XZ decompressor without a memory usage limit. |
| public | SeekableXZInputStream(SeekableInputStream
seekable input stream containing one or more
XZ Streams; the whole input stream is used in, ArrayCache cache to be used for allocating large arrays arrayCache)Creates a new seekable XZ decompressor without a memory usage limit. |
| public | SeekableXZInputStream(SeekableInputStream
seekable input stream containing one or more
XZ Streams; the whole input stream is used in, int memory usage limit in kibibytes (KiB)
or memoryLimit)-1 to impose no
memory usage limitCreates a new seekable XZ decomporessor with an optional memory usage limit. |
| public | SeekableXZInputStream(SeekableInputStream
seekable input stream containing one or more
XZ Streams; the whole input stream is used in, int memory usage limit in kibibytes (KiB)
or memoryLimit, ArrayCache -1 to impose no
memory usage limitcache to be used for allocating large arrays arrayCache)Creates a new seekable XZ decomporessor with an optional memory usage limit. |
| public | SeekableXZInputStream(SeekableInputStream
seekable input stream containing one or more
XZ Streams; the whole input stream is used in, int memory usage limit in kibibytes (KiB)
or memoryLimit, boolean -1 to impose no
memory usage limitif verifyCheck)true, the integrity checks
will be verified; this should almost never
be set to falseCreates a new seekable XZ decomporessor with an optional memory usage limit and ability to disable verification of integrity checks. |
| public | SeekableXZInputStream(SeekableInputStream
seekable input stream containing one or more
XZ Streams; the whole input stream is used in, int memory usage limit in kibibytes (KiB)
or memoryLimit, boolean -1 to impose no
memory usage limitif verifyCheck, ArrayCache true, the integrity checks
will be verified; this should almost never
be set to falsecache to be used for allocating large arrays arrayCache)Creates a new seekable XZ decomporessor with an optional memory usage limit and ability to disable verification of integrity checks. |
| Modifier and Type | Method and Description |
|---|---|
| public int | Returns: the number of uncompressed bytes that can be read without blockingOverrides java. |
| public void | close()
Overrides java. Implements java. in.close().
|
| public void | |
| public int | |
| public long | getBlockCompPos(int blockNumber)
Gets the position where the given compressed Block starts in the underlying .xz file. |
| public long | |
| public int | |
| public int | getBlockNumber(long pos)
Gets the number of the Block that contains the byte at the given uncompressed position. |
| public long | |
| public long | |
| public int | |
| public int | getIndexMemoryUsage()
Gets the amount of memory in kibibytes (KiB) used by the data structures needed to locate the XZ Blocks. |
| public long | |
| public int | |
| private void | |
| public long | length()
Implements abstract org. |
| private void | locateBlockByNumber(BlockInfo info, int blockNumber)
Locates the given Block and stores information about it
to |
| private void | locateBlockByPos(BlockInfo info, long pos)
Locates the Block that contains the given uncompressed position. |
| public long | position()
Implements abstract org. |
| public int | Returns: the next decompressed byte, or-1
to indicate the end of the compressed streamImplements abstract java. |
| public int | Returns: number of bytes read, or-1 to indicate
the end of the compressed streamtarget buffer for uncompressed data buf, int start offset in off, int bufmaximum number of uncompressed bytes to read len)Overrides java. |
| public void | seek(long
new uncompressed read position pos)Implements abstract org. |
| private void | |
| public void |
| arrayCache | back to summary |
|---|---|
| private final ArrayCache arrayCache Cache for big arrays. | |
| blockCount | back to summary |
|---|---|
| private int blockCount Number of XZ Blocks in the file. | |
| blockDecoder | back to summary |
|---|---|
| private BlockInputStream blockDecoder Decoder of the current XZ Block, if any. | |
| check | back to summary |
|---|---|
| private Check check Integrity Check in the current XZ Stream. The constructor leaves this to point to the Check of the first Stream. | |
| checkTypes | back to summary |
|---|---|
| private int checkTypes Bitmask of all Check IDs seen. | |
| curBlockInfo | back to summary |
|---|---|
| private final BlockInfo curBlockInfo Size and position information about the current Block.
If there are no Blocks, all values will be | |
| curPos | back to summary |
|---|---|
| private long curPos Current uncompressed position. | |
| endReached | back to summary |
|---|---|
| private boolean endReached True when end of the file was reached. This can be cleared by
calling | |
| exception | back to summary |
|---|---|
| private IOException exception Pending exception from an earlier error. | |
| in | back to summary |
|---|---|
| private SeekableInputStream in The input stream containing XZ compressed data. | |
| indexMemoryUsage | back to summary |
|---|---|
| private int indexMemoryUsage Memory usage of the IndexDecoders.
| |
| largestBlockSize | back to summary |
|---|---|
| private long largestBlockSize Uncompressed size of the largest XZ Block in the file. | |
| memoryLimit | back to summary |
|---|---|
| private final int memoryLimit Memory usage limit after the memory usage of the IndexDecoders have been substracted. | |
| queriedBlockInfo | back to summary |
|---|---|
| private final BlockInfo queriedBlockInfo Temporary (and cached) information about the Block whose information
is queried via | |
| seekNeeded | back to summary |
|---|---|
| private boolean seekNeeded True when | |
| seekPos | back to summary |
|---|---|
| private long seekPos Target position for seeking. | |
| streams | back to summary |
|---|---|
| private final ArrayList<IndexDecoder> streams List of IndexDecoders, one for each Stream in the file. The list is in reverse order: The first element is the last Stream in the file. | |
| tempBuf | back to summary |
|---|---|
| private final byte[] tempBuf Temporary buffer for read(). This avoids reallocating memory on every read() call. | |
| uncompressedSize | back to summary |
|---|---|
| private long uncompressedSize Uncompressed size of the file (all Streams). | |
| verifyCheck | back to summary |
|---|---|
| private final boolean verifyCheck Flag indicating if the integrity checks will be verified. | |
| SeekableXZInputStream | back to summary |
|---|---|
| public SeekableXZInputStream(SeekableInputStream in) throws IOException Creates a new seekable XZ decompressor without a memory usage limit.
| |
| SeekableXZInputStream | back to summary |
|---|---|
| public SeekableXZInputStream(SeekableInputStream in, ArrayCache arrayCache) throws IOException Creates a new seekable XZ decompressor without a memory usage limit.
This is identical to
| |
| SeekableXZInputStream | back to summary |
|---|---|
| public SeekableXZInputStream(SeekableInputStream in, int memoryLimit) throws IOException Creates a new seekable XZ decomporessor with an optional memory usage limit.
| |
| SeekableXZInputStream | back to summary |
|---|---|
| public SeekableXZInputStream(SeekableInputStream in, int memoryLimit, ArrayCache arrayCache) throws IOException Creates a new seekable XZ decomporessor with an optional memory usage limit.
This is identical to
| |
| SeekableXZInputStream | back to summary |
|---|---|
| public SeekableXZInputStream(SeekableInputStream in, int memoryLimit, boolean verifyCheck) throws IOException Creates a new seekable XZ decomporessor with an optional memory usage limit and ability to disable verification of integrity checks. Note that integrity check verification should almost never be disabled. Possible reasons to disable integrity check verification:
| |
| SeekableXZInputStream | back to summary |
|---|---|
| public SeekableXZInputStream(SeekableInputStream in, int memoryLimit, boolean verifyCheck, ArrayCache arrayCache) throws IOException Creates a new seekable XZ decomporessor with an optional memory usage limit and ability to disable verification of integrity checks.
This is identical to
| |
| available | back to summary |
|---|---|
| public int available() throws IOException Overrides java. Returns the number of uncompressed bytes that can be read
without blocking. The value is returned with an assumption
that the compressed input data will be valid. If the compressed
data is corrupt,
| |
| close | back to summary |
|---|---|
| public void close() throws IOException Overrides java. Implements java. Closes the stream and calls
This is equivalent to
| |
| close | back to summary |
|---|---|
| public void close(boolean closeInput) throws IOException Closes the stream and optionally calls
If you don't want to close the underlying
Note that if you successfully reach the end of the stream
(
| |
| getBlockCheckType | back to summary |
|---|---|
| public int getBlockCheckType(int blockNumber) Gets integrity check type (Check ID) of the given Block.
| |
| getBlockCompPos | back to summary |
|---|---|
| public long getBlockCompPos(int blockNumber) Gets the position where the given compressed Block starts in the underlying .xz file. This information is rarely useful to the users of this class.
| |
| getBlockCompSize | back to summary |
|---|---|
| public long getBlockCompSize(int blockNumber) Gets the compressed size of the given Block. This together with the uncompressed size can be used to calculate the compression ratio of the specific Block.
| |
| getBlockCount | back to summary |
|---|---|
| public int getBlockCount() Gets the number of Blocks in the .xz file.
| |
| getBlockNumber | back to summary |
|---|---|
| public int getBlockNumber(long pos) Gets the number of the Block that contains the byte at the given uncompressed position.
| |
| getBlockPos | back to summary |
|---|---|
| public long getBlockPos(int blockNumber) Gets the uncompressed start position of the given Block.
| |
| getBlockSize | back to summary |
|---|---|
| public long getBlockSize(int blockNumber) Gets the uncompressed size of the given Block.
| |
| getCheckTypes | back to summary |
|---|---|
| public int getCheckTypes() Gets the types of integrity checks used in the .xz file. Multiple checks are possible only if there are multiple concatenated XZ Streams.
The returned value has a bit set for every check type that is present.
For example, if CRC64 and SHA-256 were used, the return value is
| |
| getIndexMemoryUsage | back to summary |
|---|---|
| public int getIndexMemoryUsage() Gets the amount of memory in kibibytes (KiB) used by the data structures needed to locate the XZ Blocks. This is usually useless information but since it is calculated for memory usage limit anyway, it is nice to make it available to too. | |
| getLargestBlockSize | back to summary |
|---|---|
| public long getLargestBlockSize() Gets the uncompressed size of the largest XZ Block in bytes. This can be useful if you want to check that the file doesn't have huge XZ Blocks which could make seeking to arbitrary offsets very slow. Note that huge Blocks don't automatically mean that seeking would be slow, for example, seeking to the beginning of any Block is always fast. | |
| getStreamCount | back to summary |
|---|---|
| public int getStreamCount() Gets the number of Streams in the .xz file.
| |
| initBlockDecoder | back to summary |
|---|---|
| private void initBlockDecoder() throws IOException Initializes a new BlockInputStream. This is a helper function for
| |
| length | back to summary |
|---|---|
| public long length() Implements abstract org. Gets the uncompressed size of this input stream. If there are multiple XZ Streams, the total uncompressed size of all XZ Streams is returned. | |
| locateBlockByNumber | back to summary |
|---|---|
| private void locateBlockByNumber(BlockInfo info, int blockNumber) Locates the given Block and stores information about it
to | |
| locateBlockByPos | back to summary |
|---|---|
| private void locateBlockByPos(BlockInfo info, long pos) Locates the Block that contains the given uncompressed position. | |
| position | back to summary |
|---|---|
| public long position() throws IOException Implements abstract org. Gets the current uncompressed position in this input stream.
| |
| read | back to summary |
|---|---|
| public int read() throws IOException Implements abstract java. Decompresses the next byte from this input stream.
| |
| read | back to summary |
|---|---|
| public int read(byte[] buf, int off, int len) throws IOException Overrides java. Decompresses into an array of bytes.
If
| |
| seek | back to summary |
|---|---|
| public void seek(long pos) throws IOException Implements abstract org. Seeks to the specified absolute uncompressed position in the stream.
This only stores the new position, so this function itself is always
very fast. The actual seek is done when
Seeking past the end of the stream is possible. In that case
| |
| seek | back to summary |
|---|---|
| private void seek() throws IOException Does the actual seeking. This is also called when | |
| seekToBlock | back to summary |
|---|---|
| public void seekToBlock(int blockNumber) throws IOException Seeks to the beginning of the given XZ Block.
| |