Support This Project Flattr this SourceForge.net Logo YourKit Logo

LogoLogo Big

Extraction code snippets

Index

Extracting & browsing existing archives

Overview

Here you can find many code snippets, example of how to perform basic operations with 7-Zip-JBinding. All examples are part of the JUnit tests. Each example runs on one of the test archives. JUnit tests check, that the output of the snippet is exactly the one published on this page. Below is a list of the test archives for this page. You can download all test archives in as a single ZIP file.

  • simple.zip
    $ 7z l simple.zip
    7-Zip 4.65  Copyright (c) 1999-2009 Igor Pavlov  2009-02-03
    p7zip Version 4.65 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)
    Listing archive: simple.zip
       Date      Time    Attr         Size   Compressed  Name
    ------------------- ----- ------------ ------------  ------------------------
    2009-08-04 11:26:16 .....         4481           68  file1.txt
    2009-08-04 11:27:34 .....           75           62  file2.txt
    2009-08-04 13:53:06 D....            0            0  folder
    2009-08-04 13:53:40 .....            6            6  folder/file in folder.txt
    ------------------- ----- ------------ ------------  ------------------------
                                      4562          136  3 files, 1 folders
    
  • multipart-7z.7z.001; multipart-7z.7z.002; multipart-7z.7z.003; multipart-7z.7z.004
    $ 7z l multipart-7z.7z.001
    7-Zip 4.65  Copyright (c) 1999-2009 Igor Pavlov  2009-02-03
    p7zip Version 4.65 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)
    Listing archive: multipart-7z.7z.001
    Method = LZMA
    Solid = +
    Blocks = 1
    Physical Size = 331
    Headers Size = 217
       Date      Time    Attr         Size   Compressed  Name
    ------------------- ----- ------------ ------------  ------------------------
    2009-08-04 13:53:39 ....A            6          114  folder/file in folder.txt
    2009-08-04 11:26:16 ....A         4481               file1.txt
    2009-08-04 11:27:33 ....A           75               file2.txt
    2009-08-04 13:53:05 D....            0            0  folder
    ------------------- ----- ------------ ------------  ------------------------
                                      4562          114  3 files, 1 folders
    
  • multipart-rar.part1.rar; multipart-rar.part2.rar; multipart-rar.part3.rar; multipart-rar.part4.rar; multipart-rar.part5.rar
    $ 7z l multipart-rar.part1.rar 
    7-Zip 4.65  Copyright (c) 1999-2009 Igor Pavlov  2009-02-03
    p7zip Version 4.65 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,2 CPUs)
    Listing archive: multipart-rar.part1.rar
    Solid = -
    Blocks = 4
    Multivolume = +
    Volumes = 5
       Date      Time    Attr         Size   Compressed  Name
    ------------------- ----- ------------ ------------  ------------------------
    2009-08-04 13:53:39 .....            6            6  folder/file in folder.txt
    2009-08-04 11:26:16 .....         4481         4481  file1.txt
    2009-08-04 11:27:33 .....           75           75  file2.txt
    2009-08-04 13:53:05 D....            0            0  folder
    ------------------- ----- ------------ ------------  ------------------------
                                      4562         4562  3 files, 1 folders
    

Standard vs Simple interface

The 7-Zip-JBinding library offers two different interfaces: standard and simple. The standard interface directly maps all native 7-Zip library methods providing C++ like interface. The simple interface is a try to provide more Java-like easy to use interface. It was designed either for quick coding and easy start and not for feature richness nor for performance.

The following examples will be presented in both standard and simple interface beginning with as simple interface. Please note, that the full performance can only be reached with the standard interface.


Quering items in archive

Simple interface

This example shows how to print a list of items of archive using simple interface.

import java.io.IOException;
import java.io.RandomAccessFile;

import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;

public class ListItemsSimple {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java ListItemsSimple <archive-name>");
            return;
        }
        RandomAccessFile randomAccessFile = null;
        IInArchive inArchive = null;
        try {
            randomAccessFile = new RandomAccessFile(args[0], "r");
            inArchive = SevenZip.openInArchive(null, // autodetect archive type
                    new RandomAccessFileInStream(randomAccessFile));

            // Getting simple interface of the archive inArchive
            ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();

            System.out.println("   Size   | Compr.Sz. | Filename");
            System.out.println("----------+-----------+---------");

            for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
                System.out.println(String.format("%9s | %9s | %s", // 
                        item.getSize(), 
                        item.getPackedSize(), 
                        item.getPath()));
            }
        } catch (Exception e) {
            System.err.println("Error occurs: " + e);
        } finally {
            if (inArchive != null) {
                try {
                    inArchive.close();
                } catch (SevenZipException e) {
                    System.err.println("Error closing archive: " + e);
                }
            }
            if (randomAccessFile != null) {
                try {
                    randomAccessFile.close();
                } catch (IOException e) {
                    System.err.println("Error closing file: " + e);
                }
            }
        }
    }
}

The output for the test archive:

   Size   | Compr.Sz. | Filename
----------+-----------+---------
     4481 |        68 | file1.txt
       75 |        62 | file2.txt
        0 |         0 | folder
        6 |         6 | folder/file in folder.txt

Please note, that not all archive formats support the "folder" items, like "folder/" in our example. Also please note, that packed size in this example as almost all other properties can return null. A returned null value means, that either the property is not supported by the particular archive format or not known for the particular item.

Standard interface

This example shows how to print a list of items of archive using standard interface.

import java.io.IOException;
import java.io.RandomAccessFile;

import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;

public class ListItemsStandard {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java ListItemsStandard <archive-name>");
            return;
        }
        RandomAccessFile randomAccessFile = null;
        IInArchive inArchive = null;
        try {
            randomAccessFile = new RandomAccessFile(args[0], "r");
            inArchive = SevenZip.openInArchive(null, // autodetect archive type
                    new RandomAccessFileInStream(randomAccessFile));

            System.out.println("   Size   | Compr.Sz. | Filename");
            System.out.println("----------+-----------+---------");
            int itemCount = inArchive.getNumberOfItems();
            for (int i = 0; i < itemCount; i++) {
                System.out.println(String.format("%9s | %9s | %s", // 
                        inArchive.getProperty(i, PropID.SIZE), 
                        inArchive.getProperty(i, PropID.PACKED_SIZE), 
                        inArchive.getProperty(i, PropID.PATH)));
            }
        } catch (Exception e) {
            System.err.println("Error occurs: " + e);
        } finally {
            if (inArchive != null) {
                try {
                    inArchive.close();
                } catch (SevenZipException e) {
                    System.err.println("Error closing archive: " + e);
                }
            }
            if (randomAccessFile != null) {
                try {
                    randomAccessFile.close();
                } catch (IOException e) {
                    System.err.println("Error closing file: " + e);
                }
            }
        }
    }
}

The output for the test archive is the same:

   Size   | Compr.Sz. | Filename
----------+-----------+---------
     4481 |        68 | file1.txt
       75 |        62 | file2.txt
        0 |         0 | folder
        6 |         6 | folder/file in folder.txt

Extracting of a single file

This section will show how to access the compressed data of the archive items. The following examples will calculate a simple checksum of each archive item.

Simple interface

This example shows how to get content of the items of the archive using simple interface. In order to consume extracted content the simple checksum will be calculated.

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;

import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.simple.ISimpleInArchive;
import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem;

public class ExtractItemsSimple {
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java ExtractItemsSimple <archive-name>");
            return;
        }
        RandomAccessFile randomAccessFile = null;
        IInArchive inArchive = null;
        try {
            randomAccessFile = new RandomAccessFile(args[0], "r");
            inArchive = SevenZip.openInArchive(null, // autodetect archive type
                    new RandomAccessFileInStream(randomAccessFile));

            // Getting simple interface of the archive inArchive
            ISimpleInArchive simpleInArchive = inArchive.getSimpleInterface();

            System.out.println("   Hash   |    Size    | Filename");
            System.out.println("----------+------------+---------");

            for (ISimpleInArchiveItem item : simpleInArchive.getArchiveItems()) {
                final int[] hash = new int[] { 0 };
                if (!item.isFolder()) {
                    ExtractOperationResult result;

                    final long[] sizeArray = new long[1];
                    result = item.extractSlow(new ISequentialOutStream() {
                        public int write(byte[] data) throws SevenZipException {
                            hash[0] ^= Arrays.hashCode(data); // Consume data
                            sizeArray[0] += data.length;
                            return data.length; // Return amount of consumed data
                        }
                    });

                    if (result == ExtractOperationResult.OK) {
                        System.out.println(String.format("%9X | %10s | %s", 
                                hash[0], sizeArray[0], item.getPath()));
                    } else {
                        System.err.println("Error extracting item: " + result);
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("Error occurs: " + e);
        } finally {
            if (inArchive != null) {
                try {
                    inArchive.close();
                } catch (SevenZipException e) {
                    System.err.println("Error closing archive: " + e);
                }
            }
            if (randomAccessFile != null) {
                try {
                    randomAccessFile.close();
                } catch (IOException e) {
                    System.err.println("Error closing file: " + e);
                }
            }
        }
    }
}

Here is the output of the last snippet:

   Hash   |    Size    | Filename
----------+------------+---------
 C1FD1029 |       4481 | file1.txt
 8CB12E6A |         75 | file2.txt
 E8EEC7F4 |          6 | folder/file in folder.txt

Standard interface

The following two examples show how to perform the same extracting task using standard interface. As in the previous example, the simple checksum will be calculated in order to consume the extracted data.

First example traverse the entire archive and uses call back method to choose on the fly whether proceed with the extracting of an item or not. The second example prepare a list of items for extracting.

Extracting archive using standard interface and call back method as a filter

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;

import net.sf.sevenzipjbinding.ExtractAskMode;
import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.IArchiveExtractCallback;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;

public class ExtractItemsStandardCallback {
    public static class MyExtractCallback implements IArchiveExtractCallback {
        private int hash = 0;
        private int size = 0;
        private int index;
        private boolean skipExtraction;
        private IInArchive inArchive;

        public MyExtractCallback(IInArchive inArchive) {
            this.inArchive = inArchive;
        }

        public ISequentialOutStream getStream(int index, 
                ExtractAskMode extractAskMode) throws SevenZipException {
            this.index = index;
            skipExtraction = (Boolean) inArchive
                    .getProperty(index, PropID.IS_FOLDER);
            if (skipExtraction || extractAskMode != ExtractAskMode.EXTRACT) {
                return null;
            }
            return new ISequentialOutStream() {
                public int write(byte[] data) throws SevenZipException {
                    hash ^= Arrays.hashCode(data);
                    size += data.length;
                    return data.length; // Return amount of proceed data
                }
            };
        }

        public void prepareOperation(ExtractAskMode extractAskMode) 
                throws SevenZipException {
        }

        public void setOperationResult(ExtractOperationResult 
                extractOperationResult) throws SevenZipException {
            if (skipExtraction) {
                return;
            }
            if (extractOperationResult != ExtractOperationResult.OK) {
                System.err.println("Extraction error");
            } else {
                System.out.println(String.format("%9X | %10s | %s", hash, size,// 
                        inArchive.getProperty(index, PropID.PATH)));
                hash = 0;
                size = 0;
            }
        }

        public void setCompleted(long completeValue) throws SevenZipException {
        }

        public void setTotal(long total) throws SevenZipException {
        }
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java ExtractItemsStandard <arch-name>");
            return;
        }
        RandomAccessFile randomAccessFile = null;
        IInArchive inArchive = null;
        try {
            randomAccessFile = new RandomAccessFile(args[0], "r");
            inArchive = SevenZip.openInArchive(null, // autodetect archive type
                    new RandomAccessFileInStream(randomAccessFile));

            System.out.println("   Hash   |    Size    | Filename");
            System.out.println("----------+------------+---------");

            int[] in = new int[inArchive.getNumberOfItems()];
            for (int i = 0; i < in.length; i++) {
                in[i] = i;
            }
            inArchive.extract(in, false, // Non-test mode
                    new MyExtractCallback(inArchive));
        } catch (Exception e) {
            System.err.println("Error occurs: " + e);
        } finally {
            if (inArchive != null) {
                try {
                    inArchive.close();
                } catch (SevenZipException e) {
                    System.err.println("Error closing archive: " + e);
                }
            }
            if (randomAccessFile != null) {
                try {
                    randomAccessFile.close();
                } catch (IOException e) {
                    System.err.println("Error closing file: " + e);
                }
            }
        }
    }
}

Extracting archive using standard interface and prepared list of items to extract

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.sf.sevenzipjbinding.ExtractAskMode;
import net.sf.sevenzipjbinding.ExtractOperationResult;
import net.sf.sevenzipjbinding.IArchiveExtractCallback;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.ISequentialOutStream;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;

public class ExtractItemsStandard {
    public static class MyExtractCallback implements IArchiveExtractCallback {
        private int hash = 0;
        private int size = 0;
        private int index;
        private IInArchive inArchive;

        public MyExtractCallback(IInArchive inArchive) {
            this.inArchive = inArchive;
        }

        public ISequentialOutStream getStream(int index, 
                ExtractAskMode extractAskMode) throws SevenZipException {
            this.index = index;
            if (extractAskMode != ExtractAskMode.EXTRACT) {
                return null;
            }
            return new ISequentialOutStream() {

                public int write(byte[] data) throws SevenZipException {
                    hash ^= Arrays.hashCode(data);
                    size += data.length;
                    return data.length; // Return amount of proceed data
                }
            };
        }

        public void prepareOperation(ExtractAskMode extractAskMode) 
                throws SevenZipException {
        }

        public void setOperationResult(ExtractOperationResult 
                extractOperationResult) throws SevenZipException {
            if (extractOperationResult != ExtractOperationResult.OK) {
                System.err.println("Extraction error");
            } else {
                System.out.println(String.format("%9X | %10s | %s", hash, size,
                        inArchive.getProperty(index, PropID.PATH)));
                hash = 0;
                size = 0;
            }
        }

        public void setCompleted(long completeValue) throws SevenZipException {
        }

        public void setTotal(long total) throws SevenZipException {
        }

    }

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("Usage: java ExtractItemsStandard <arch-name>");
            return;
        }
        RandomAccessFile randomAccessFile = null;
        IInArchive inArchive = null;
        try {
            randomAccessFile = new RandomAccessFile(args[0], "r");
            inArchive = SevenZip.openInArchive(null, // autodetect archive type
                    new RandomAccessFileInStream(randomAccessFile));

            System.out.println("   Hash   |    Size    | Filename");
            System.out.println("----------+------------+---------");

            int count = inArchive.getNumberOfItems();
            List<Integer> itemsToExtract = new ArrayList<Integer>();
            for (int i = 0; i < count; i++) {
                if (!((Boolean) inArchive.getProperty(i, PropID.IS_FOLDER))
                        .booleanValue()) {
                    itemsToExtract.add(Integer.valueOf(i));
                }
            }
            int[] items = new int[itemsToExtract.size()];
            int i = 0;
            for (Integer integer : itemsToExtract) {
                items[i++] = integer.intValue();
            }
            inArchive.extract(items, false, // Non-test mode
                    new MyExtractCallback(inArchive));
        } catch (Exception e) {
            System.err.println("Error occurs: " + e);
        } finally {
            if (inArchive != null) {
                try {
                    inArchive.close();
                } catch (SevenZipException e) {
                    System.err.println("Error closing archive: " + e);
                }
            }
            if (randomAccessFile != null) {
                try {
                    randomAccessFile.close();
                } catch (IOException e) {
                    System.err.println("Error closing file: " + e);
                }
            }
        }
    }
}

Open multi-part archives

Dealing with a multi-part archives is not so easy, as dealing with a ordinary single part archives. Different archive formats need different approaches and therefore will be discussed separately.

Open multi-part 7z archives

Multi-part 7z archives are build by simple splitting of solid 7z archives into multiple peaces. This means, you can easy convert a multi-part 7z archive into single part 7z archive by concatenation of all archive parts into a one single file. Here is an example, how you can do this in a sh-shell.

$ ###
$ ### Compress some files into 7z archive.
$ ### Create mult-part archive 10.240 bytes for each part.
$ ###
$ 7z a test.7z -v10k somedir/
...
$ ls -l
total 32
-rw-r--r-- 1 boris boris 10240 2009-11-29 01:17 test.7z.001
-rw-r--r-- 1 boris boris 10240 2009-11-29 01:17 test.7z.002
-rw-r--r-- 1 boris boris  6684 2009-11-29 01:17 test.7z.003
$ ###
$ ### Concatenate all parts into a single file
$ ###
$ cat test.7z.* > test.7z
$ ls -l
total 60
-rw-r--r-- 1 boris boris 27164 2009-11-29 01:18 test.7z
-rw-r--r-- 1 boris boris 10240 2009-11-29 01:17 test.7z.001
-rw-r--r-- 1 boris boris 10240 2009-11-29 01:17 test.7z.002
-rw-r--r-- 1 boris boris  6684 2009-11-29 01:17 test.7z.003
$ ###
$ ### Test archive
$ ###
$ 7z t test.7z
...
Everything is Ok
...
###
### Split solid archive back into peaces
### Split starts counting from 000, so rename files
###
$ split  -b 15000 -a 3 -d test.7z test2.7z.
$ mv test2.7z.001 test2.7z.002
$ mv test2.7z.000 test2.7z.001
$ ls -l
total 88
-rw-r--r-- 1 boris boris 15000 2009-11-29 01:36 test2.7z.001
-rw-r--r-- 1 boris boris 12164 2009-11-29 01:36 test2.7z.002
-rw-r--r-- 1 boris boris 27164 2009-11-29 01:22 test.7z
-rw-r--r-- 1 boris boris 10240 2009-11-29 01:17 test.7z.001
-rw-r--r-- 1 boris boris 10240 2009-11-29 01:17 test.7z.002
-rw-r--r-- 1 boris boris  6684 2009-11-29 01:17 test.7z.003
$ ###
$ ### Test new multi-part archive file archive
$ ###
$ 7z t test2.7z.001
...
Everything is Ok
...

The naming conventions for the volumes of a multi-part 7z archive are:

  • Every file name of a volume should ends with ".7z.XXX", where X is a digit between 0 and 9. The XXX is a decimal sequential number of the volume starting with 1. Ending ".7z.000" is not allowed.

It's important to provide corrent names in IArchiveOpenVolumeCallback.getProperty() method and to VolumedArchiveInStream class. Also you will probably need to parse filenames passed to IArchiveOpenVolumeCallback.getStream(String filename) in order to get a number of the required volume.

Here is an example of how to open a multi-part archive directly from the file system. In this example all the volumes are named correctly, so it's no need to parse requred volume name to extract the index. The volumes already exists under the passed names und can be directly opened.

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;

import net.sf.sevenzipjbinding.ArchiveFormat;
import net.sf.sevenzipjbinding.IArchiveOpenVolumeCallback;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.IInStream;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;
import net.sf.sevenzipjbinding.impl.VolumedArchiveInStream;

public class OpenMultipartArchive7z {
    /**
     * In this example we use VolumedArchiveInStream class only.
     * It means, we doesn't pass instances of this class directly
     * to 7-Zip, so not complete implementation
     * of {@link IArchiveOpenVolumeCallback} is required.
     * See VolumedArchiveInStream JavaDoc for more information
     */
    private static class ArchiveOpenVolumeCallback 
            implements IArchiveOpenVolumeCallback {

        /**
         * Cache for opened file streams
         */
        private Map<String, RandomAccessFile> openedRandomAccessFileList = 
                        new HashMap<String, RandomAccessFile>();

        /**
         * This method doesn't needed, if using with VolumedArchiveInStream
         * and pass the name of the first archive in constructor.
         * (Use two argument constructor)
         * 
         * @see IArchiveOpenVolumeCallback#getProperty(PropID)
         */
        public Object getProperty(PropID propID) throws SevenZipException {
            return null;
        }

        /**
         * 
         * The name of the required volume will be calculated out of the
         * name of the first volume and volume index. If you need
         * need volume index (integer) you will have to parse filename
         * and extract index.
         * 
         * <pre>
         * int index = filename.substring(filename.length() - 3, 
         *         filename.length());
         * </pre>
         * 
         */
        public IInStream getStream(String filename) throws SevenZipException {
            try {
                // We use caching of opened streams, so check cache first
                RandomAccessFile randomAccessFile = openedRandomAccessFileList
                        .get(filename);
                if (randomAccessFile != null) { // Cache hit.
                    // Move the file pointer back to the beginning
                    // in order to emulating new stream
                    randomAccessFile.seek(0);
                    return new RandomAccessFileInStream(randomAccessFile);
                }

                // Nothing useful in cache. Open required volume.
                randomAccessFile = new RandomAccessFile(filename, "r");

                // Put new stream in the cache
                openedRandomAccessFileList.put(filename, randomAccessFile);

                return new RandomAccessFileInStream(randomAccessFile);
            } catch (FileNotFoundException fileNotFoundException) {
                // Required volume doesn't exist. This happens if the volume:
                // 1. never exists. 7-Zip doesn't know how many volumes should
                //    exist, so it have to try each volume.
                // 2. should be there, but doesn't. This is an error case.

                // Since normal and error cases are possible,
                // we can't throw an error message
                return null; // We return always null in this case
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * Close all opened streams
         */
        void close() throws IOException {
            for (RandomAccessFile file : openedRandomAccessFileList.values()) {
                file.close();
            }
        }
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println(
                    "Usage: java OpenMultipartArchive7z <first-volume>");
            return;
        }
        ArchiveOpenVolumeCallback archiveOpenVolumeCallback = null;
        IInArchive inArchive = null;
        try {

            archiveOpenVolumeCallback = new ArchiveOpenVolumeCallback();
            inArchive = SevenZip.openInArchive(ArchiveFormat.SEVEN_ZIP, 
                    new VolumedArchiveInStream(args[0], 
                            archiveOpenVolumeCallback));

            System.out.println("   Size   | Compr.Sz. | Filename");
            System.out.println("----------+-----------+---------");
            int itemCount = inArchive.getNumberOfItems();
            for (int i = 0; i < itemCount; i++) {
                System.out.println(String.format("%9s | %9s | %s", // 
                        inArchive.getProperty(i, PropID.SIZE), 
                        inArchive.getProperty(i, PropID.PACKED_SIZE), 
                        inArchive.getProperty(i, PropID.PATH)));
            }
        } catch (Exception e) {
            System.err.println("Error occurs: " + e);
        } finally {
            if (inArchive != null) {
                try {
                    inArchive.close();
                } catch (SevenZipException e) {
                    System.err.println("Error closing archive: " + e);
                }
            }
            if (archiveOpenVolumeCallback != null) {
                try {
                    archiveOpenVolumeCallback.close();
                } catch (IOException e) {
                    System.err.println("Error closing file: " + e);
                }
            }
        }
    }
}

Here is the output of the last snippet:

   Size   | Compr.Sz. | Filename
----------+-----------+---------
        6 |       114 | folder/file in folder.txt
     4481 |      null | file1.txt
       75 |      null | file2.txt
        0 |         0 | folder

Open multi-part RAR archives

Since RAR uses its own proprietary format for splitting archives into multiple volumes, there is no need to use VolumedArchiveInStream in order to open multi-part RAR archives. To provide access to the different volumes of a RAR archive, the archive open callback class should additionally implement the IArchiveOpenVolumeCallback interface. Here is an example:

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.HashMap;
import java.util.Map;

import net.sf.sevenzipjbinding.ArchiveFormat;
import net.sf.sevenzipjbinding.IArchiveOpenCallback;
import net.sf.sevenzipjbinding.IArchiveOpenVolumeCallback;
import net.sf.sevenzipjbinding.IInArchive;
import net.sf.sevenzipjbinding.IInStream;
import net.sf.sevenzipjbinding.PropID;
import net.sf.sevenzipjbinding.SevenZip;
import net.sf.sevenzipjbinding.SevenZipException;
import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream;

public class OpenMultipartArchiveRar {
    private static class ArchiveOpenVolumeCallback 
            implements IArchiveOpenVolumeCallback, IArchiveOpenCallback {

        /**
         * Cache for opened file streams
         */
        private Map<String, RandomAccessFile> openedRandomAccessFileList = 
                        new HashMap<String, RandomAccessFile>();

        /**
         * Name of the last volume returned by {@link #getStream(String)}
         */
        private String name ;

        /**
         * This method should at least provide the name of the last
         * opened volume (propID=PropID.NAME).
         * 
         * @see IArchiveOpenVolumeCallback#getProperty(PropID)
         */
        public Object getProperty(PropID propID) throws SevenZipException {
            switch (propID) {
            case NAME:
                return name ;
            }
            return null;
        }

        /**
         * The name of the required volume will be calculated out of the
         * name of the first volume and a volume index. In case of RAR file,
         * the substring ".partNN." in the name of the volume file will
         * indicate a volume with id NN. For example:
         * <ul>
         * <li>test.rar - single part archive or multi-part archive with
         * a single volume</li>
         * <li>test.part23.rar - 23-th part of a multi-part archive</li>
         * <li>test.part001.rar - first part of a multi-part archive.
         * "00" indicates, that at least 100 volumes must exist.</li>
         * </ul>
         */
        public IInStream getStream(String filename) throws SevenZipException {
            try {
                // We use caching of opened streams, so check cache first
                RandomAccessFile randomAccessFile = openedRandomAccessFileList
                        .get(filename);
                if (randomAccessFile != null) { // Cache hit.
                    // Move the file pointer back to the beginning
                    // in order to emulating new stream
                    randomAccessFile.seek(0);

                    // Save current volume name in case getProperty() will be called
                    name = filename;

                    return new RandomAccessFileInStream(randomAccessFile);
                }

                // Nothing useful in cache. Open required volume.
                randomAccessFile = new RandomAccessFile(filename, "r");

                // Put new stream in the cache
                openedRandomAccessFileList.put(filename, randomAccessFile);

                // Save current volume name in case getProperty() will be called
                name = filename;
                return new RandomAccessFileInStream(randomAccessFile);
            } catch (FileNotFoundException fileNotFoundException) {
                // Required volume doesn't exist. This happens if the volume:
                // 1. never exists. 7-Zip doesn't know how many volumes should
                //    exist, so it have to try each volume.
                // 2. should be there, but doesn't. This is an error case.

                // Since normal and error cases are possible,
                // we can't throw an error message
                return null; // We return always null in this case
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        /**
         * Close all opened streams
         */
        void close() throws IOException {
            for (RandomAccessFile file : openedRandomAccessFileList.values()) {
                file.close();
            }
        }

        public void setCompleted(Long files, Long bytes) throws SevenZipException {
        }

        public void setTotal(Long files, Long bytes) throws SevenZipException {
        }
    }

    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println(
                    "Usage: java OpenMultipartArchiveRar <first-volume>");
            return;
        }
        ArchiveOpenVolumeCallback archiveOpenVolumeCallback = null;
        IInArchive inArchive = null;
        try {

            archiveOpenVolumeCallback = new ArchiveOpenVolumeCallback();
            IInStream inStream = archiveOpenVolumeCallback.getStream(args[0]);
            inArchive = SevenZip.openInArchive(ArchiveFormat.RAR, inStream, 
                    archiveOpenVolumeCallback);

            System.out.println("   Size   | Compr.Sz. | Filename");
            System.out.println("----------+-----------+---------");
            int itemCount = inArchive.getNumberOfItems();
            for (int i = 0; i < itemCount; i++) {
                System.out.println(String.format("%9s | %9s | %s", 
                        inArchive.getProperty(i, PropID.SIZE), 
                        inArchive.getProperty(i, PropID.PACKED_SIZE), 
                        inArchive.getProperty(i, PropID.PATH)));
            }
        } catch (Exception e) {
            System.err.println("Error occurs: " + e);
        } finally {
            if (inArchive != null) {
                try {
                    inArchive.close();
                } catch (SevenZipException e) {
                    System.err.println("Error closing archive: " + e);
                }
            }
            if (archiveOpenVolumeCallback != null) {
                try {
                    archiveOpenVolumeCallback.close();
                } catch (IOException e) {
                    System.err.println("Error closing file: " + e);
                }
            }
        }
    }
}

Here is the output of the last snippet:

   Size   | Compr.Sz. | Filename
----------+-----------+---------
        6 |         6 | folder/file in folder.txt
     4481 |      4481 | file1.txt
       75 |        75 | file2.txt
        0 |         0 | folder
Icons made by Freepik from www.flaticon.com