1

How can I iterate over over all the RAR archives in a directory. I know how to iterate over the files in a directory but I'm only interested in RAR archives. If they were simple RAR archives with the extension .rar it wouldn't be an issue but my directories can have multiple spanned archives and I only want the first/main volume in the set. I also would like to have the other files in the directory:

Here are the contents of a sample directory:

  • file.txt
  • somefile.zip
  • hello.rar
  • test.part1.rar
  • test.part2.rar
  • example.rar
  • example.r00

Result:

  • file.txt
  • somefile.zip
  • hello.rar
  • test.part1.rar
  • example.rar

This is what I'm using ti iterate over the directory:

  import java.io.File;

  ...

  for (File child : (new File(myDirectoryPath)).listFiles()) {
    if (!child.isDirectory()) {
      //Do something with the file
    }
  }

How can I do this? I need to detect whether it is a RAR archive or not. If it isn't, use it. If it is, I'd need to check whether it is the first part of an archive. if yes, do whatever, else ignore it.

Thanks

Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382

4 Answers4

2

The difficulty in finding a solution is that there is no set naming technique when .rar archives are spanned across multiple files. Furthermore, there's nothing preventing a user from creating a random file named as if it were one of a spanned rar parts. The only proper way to determine this would be to actually read the content of each suspect file and see if this is a continuation of the spanned rar file. Apart from being complicated, this would also be unacceptably slow.

However in most cases, the split files are named either file.rar with file.rXX (excactly 2 digits) as the continuation or file.partXXX.rar with the first file being file.part1.rar (XXX starts from 1 and goes to whatever is the max number). Therefore you can try catching these two cases using FilenameFilter with something like below.

The downside of this method is that it would discard files if they happen to be randomly named, for example, somefile.part2.rar or otherfile.r03, yet, hopefully, this would help you for the most part.

for (File child : (new File(myDirectoryPath)).listFiles(new FilenameFilter() {
    private Pattern p1 = null;
    private Pattern p2 = null;
    public boolean accept(File dir, String name) {

        name = name.toLowerCase();

        if(p1 == null) {
            p1 = Pattern.compile("\\.r\\d\\d");
            p2 = Pattern.compile("\\.part\\d+\\.rar");
        }

        if(name.endsWith(".part1.rar")) {
            return true;
        }
        else if(p2.matcher(name).matches()) {
            return false;
        }
        else {
            return !p1.matcher(name).matches();
        }
    }
}) {
    if (!child.isDirectory()) {
      //Do something with the file
    }
}
Aleks G
  • 56,435
  • 29
  • 168
  • 265
1

I've written this bit of code to identify RAR archives where I only take the first-volume of a spanned archive into consideration and omit the others.

/**
 * Checks whether a file is an archive
 *
 * @param    filFile        the file to checks
 * @retuns                  a bollean value indicating the result
 */
 public static Boolean isArchive(File filFile) {  

     try {

         byte[] bytSignature = new byte[] {0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00};
         FileInputStream fisFileInputStream = new FileInputStream(filFile);

         byte[] bytHeader = new byte[20];
         fisFileInputStream.read(bytHeader);

         Short shoFlags = (short) (((bytHeader[10]&0xFF)<<8) | (bytHeader[11]&0xFF));

         //Check if is an archive
         if (Arrays.equals(Arrays.copyOfRange(bytHeader, 0, 7), bytSignature)) {
             //Check if is a spanned archive
             if ((shoFlags & 0x0100) != 0) {
                 //Check if it the first part of a spanned archive
                 if ((shoFlags & 0x0001) != 0) {
                     return true;
                 } else {
                     return false;
                 }
             } else {
                 return true;
             }
         } else {
             return true;
         }

     } catch (Exception e) {
         return false;
     }

 }

I've used the official RAR header specifications. In order to implement this and parse the bytes, I've followed a discussion here:

How do I read in hex values from a binary file and decipher some bytes containing bitflag values?.

Community
  • 1
  • 1
Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
0

check if your file name endsWith(".rar") and put it in a set to ensure uniqueness

Set<String> fileSet=new HashSet<String>();

if(fileName.endsWith(".rar")){
    set.add(fileName);
}
Pooya
  • 4,385
  • 6
  • 45
  • 73
0

Step 1: File.listFile(FileFilter) is your friend. Implemented correctly, that will give you only the RAR's and the spanning files.

Step 2: Collect the prefixes of all names in distinct collections like proposed above.

Jochen
  • 2,277
  • 15
  • 22