94

I would like to get a list of files with a specific extension in a directory. In the API (Java 6), I see a method File.listFiles(FileFilter) which would do this.

Since I need a specific extension, I created a FileNameExtensionFilter. However I get a compilation error when I use listFiles with this. I assumed that since FileNameExtensionFilter implements FileFilter, I should be able to do this. Code follows:

FileNameExtensionFilter filter = new FileNameExtensionFilter("text only","txt");
String dir  = "/users/blah/dirname";
File f[] = (new File(dir)).listFiles(filter);

The last line shows a compilation error:

method listFiles(FileNameFilter) in type File is not applicable for arguments of type FileNameExtensionFilter

I am trying to use listFiles(FileFilter), not listFiles(FileNameFilter). Why does the compiler not recognize this?

This works if I write my own extension filter extending FileFilter. I would rather use FileNameExtensionFilter than write my own. What am I doing wrong?

msrd0
  • 7,816
  • 9
  • 47
  • 82
Anu
  • 1,337
  • 1
  • 10
  • 21

6 Answers6

195

The FileNameExtensionFilter class is intended for Swing to be used in a JFileChooser.

Try using a FilenameFilter instead. For example:

File dir = new File("/users/blah/dirname");
File[] files = dir.listFiles(new FilenameFilter() {
    public boolean accept(File dir, String name) {
        return name.toLowerCase().endsWith(".txt");
    }
});
WhiteFang34
  • 70,765
  • 18
  • 106
  • 111
53

One-liner in java 8 syntax:

pdfTestDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".txt"));
mernst
  • 7,437
  • 30
  • 45
Serġan
  • 658
  • 5
  • 6
  • 7
    You can omit curly braces and return: `pdfTestDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".txt"));` – Gabor Szarnyas Aug 24 '17 at 06:50
  • Another solution: `Files.list(Paths.get("your/path")).filter(path -> path.toString().endsWith(".txt")).collect(Collectors.toList());` – CeePlusPlus Jun 26 '20 at 05:20
31

Is there a specific reason you want to use FileNameExtensionFilter? I know this works..

private File[] getNewTextFiles() {
    return dir.listFiles(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.toLowerCase().endsWith(".txt");
        }
    });
}
CanSpice
  • 34,814
  • 10
  • 72
  • 86
CFreiner
  • 465
  • 1
  • 5
  • 12
2

With java lambdas (available since java 8) you can simply convert javax.swing.filechooser.FileFilter to java.io.FileFilter in one line.

javax.swing.filechooser.FileFilter swingFilter = new FileNameExtensionFilter("jpeg files", "jpeg");
java.io.FileFilter ioFilter = file -> swingFilter.accept(file);
new File("myDirectory").listFiles(ioFilter);
Marcin Mikosik
  • 788
  • 8
  • 21
  • Thanks, this is especially useful if you need both a `filechooser.FileFilter` and a `io.FileFilter` but only want to define it once. – j-hap Oct 10 '21 at 17:01
1

Here's something I quickly just made and it should perform far better than File.getName().endsWith(".xxxx");

import java.io.File;
import java.io.FileFilter;

public class ExtensionsFilter implements FileFilter 
{
    private char[][] extensions;

    private ExtensionsFilter(String[] extensions)
    {
        int length = extensions.length;
        this.extensions = new char[length][];
        for (String s : extensions)
        {
            this.extensions[--length] = s.toCharArray();
        }
    }

    @Override
    public boolean accept(File file)
    {
        char[] path = file.getPath().toCharArray();
        for (char[] extension : extensions)
        {
            if (extension.length > path.length)
            {
                continue;
            }
            int pStart = path.length - 1;
            int eStart = extension.length - 1;
            boolean success = true;
            for (int i = 0; i <= eStart; i++)
            {
                if ((path[pStart - i] | 0x20) != (extension[eStart - i] | 0x20))
                {
                    success = false;
                    break;
                }
            }
            if (success)
                return true;
        }
        return false;
    }
}

Here's an example for various images formats.

private static final ExtensionsFilter IMAGE_FILTER = 
      new ExtensionsFilter(new String[] {".png", ".jpg", ".bmp"});
Jeremy Trifilo
  • 456
  • 6
  • 11
  • 11
    Good, but my new mantra is to keep things simple unless they need to be more complicated, meaning, using Java API methods/classes unless I really have to write my own. – Anu Nov 05 '12 at 18:33
  • @JeremyTrifilo Why have you done path[pStart - i] | 0x20 in the code? – Sohil Nov 03 '16 at 10:36
  • 1
    Why reinvent the wheel? – james.garriss Mar 21 '17 at 14:29
  • The | 20 was for Uppercase vs Lowercase variations. It force adds 32 to the letter which makes it a lowercase letter for checking. So you could save a file as Example.PnG or Example.pNg and it would still pick it up. I don't normally redo stuff like this, but I do it because it's great learning if you can understand how these things work and what can be done to make them better. However I get what you mean it's redundant for this scenario as the performance increase is minimal and there isn't a need for this to be fast. – Jeremy Trifilo Dec 07 '18 at 22:17
0

Duh.... listFiles requires java.io.FileFilter. FileNameExtensionFilter extends javax.swing.filechooser.FileFilter. I solved my problem by implementing an instance of java.io.FileFilter

Edit: I did use something similar to @cFreiner's answer. I was trying to use a Java API method instead of writing my own implementation which is why I was trying to use FileNameExtensionFilter. I have many FileChoosers in my application and have used FileNameExtensionFilters for that and I mistakenly assumed that it was also extending java.io.FileFilter.

Anu
  • 1,337
  • 1
  • 10
  • 21