41

I have around 500 text files inside a directory with each with the same prefix in their filename, for example: dailyReport_.

The latter part of the file is the date of the file. (For example dailyReport_08262011.txt, dailyReport_08232011.txt)

I want to delete these files using a Java procedure. (I could go for a shell script and add it a job in the crontab but the application is meant to used by laymen).

I can delete a single file using something like this:

try{
    File f=new File("dailyReport_08232011.txt");
    f.delete();
}
catch(Exception e){ 
    System.out.println(e);
}

but can I delete the files having a certain prefix? (e.g. dailyReport08 for the 8th month) I could easily do that in shell script by using rm -rf dailyReport08*.txt .

But File f=new File("dailyReport_08*.txt"); doesnt work in Java (as expected).

Now is anything similar possible in Java without running a loop that searches the directory for files?

Can I achieve this using some special characters similar to * used in shell script?

Abra
  • 19,142
  • 7
  • 29
  • 41
Sangeet Menon
  • 9,555
  • 8
  • 40
  • 58
  • 4
    What wrong with looping? – user802421 Aug 30 '11 at 08:32
  • i also feels the same... why not loop? – amod Aug 30 '11 at 08:32
  • I know its possible with loop...but as I said I might be having a large number of files(500 is just a number)...so instead of using a loop if its possible the other way around like a shell script I feel that would be better... – Sangeet Menon Aug 30 '11 at 08:35
  • 2
    @S.M.09: so you want to do something on a big number on inputs. Sounds like you need a loop. Again: **why** don't you want a loop? Do you think it's somehow slower? Hint: even the shell will need to loop at some point, you just don't *see* that loop. – Joachim Sauer Aug 30 '11 at 08:39
  • 1
    If you like the shell, there is an answer to [this question](http://stackoverflow.com/questions/2111983/java-runtime-getruntime-exec-wildcards) that may help. – Ray Toal Aug 30 '11 at 08:39

11 Answers11

50

No, you can't. Java is rather low-level language -- comparing with shell-script -- so things like this must be done more explicetly. You should search for files with required mask with folder.listFiles(FilenameFilter), and iterate through returned array deleting each entry. Like this:

final File folder = ...
final File[] files = folder.listFiles( new FilenameFilter() {
    @Override
    public boolean accept( final File dir,
                           final String name ) {
        return name.matches( "dailyReport_08.*\\.txt" );
    }
} );
for ( final File file : files ) {
    if ( !file.delete() ) {
        System.err.println( "Can't remove " + file.getAbsolutePath() );
    }
}
BegemoT
  • 3,776
  • 1
  • 24
  • 30
  • Thumb up! No for loop at all. – user802421 Aug 30 '11 at 09:14
  • @user802421: There is a for loop but, I intended to avoid a loop for searching files with pattern...and as I said this gives a faster result to a logic I tried with a loop searching for files and deleting when found one.... – Sangeet Menon Sep 02 '11 at 05:27
  • These days you could just replace the FilenameFilter object with a lambda: folder.listFiles((dir, name) -> name.matches("dailyReport_08.*\\.txt")); – SomeGuy Oct 09 '21 at 18:51
41

You can use a loop

for (File f : directory.listFiles()) {
    if (f.getName().startsWith("dailyReport_")) {
        f.delete();
    }
}
Luciano van der Veekens
  • 6,307
  • 4
  • 26
  • 30
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
12

Java 8 :

final File downloadDirectory = new File("directoryPath");   
    final File[] files = downloadDirectory.listFiles( (dir,name) -> name.matches("dailyReport_.*?" ));
    Arrays.asList(files).stream().forEach(File::delete)
Niraj Sonawane
  • 10,225
  • 10
  • 75
  • 104
10

With Java 8:

public static boolean deleteFilesForPathByPrefix(final String path, final String prefix) {
    boolean success = true;
    try (DirectoryStream<Path> newDirectoryStream = Files.newDirectoryStream(Paths.get(path), prefix + "*")) {
        for (final Path newDirectoryStreamItem : newDirectoryStream) {
            Files.delete(newDirectoryStreamItem);
        }
    } catch (final Exception e) {
        success = false;
        e.printStackTrace();
    }
    return success;
}

Simple version:

public static void deleteFilesForPathByPrefix(final Path path, final String prefix) {
    try (DirectoryStream<Path> newDirectoryStream = Files.newDirectoryStream(path, prefix + "*")) {
        for (final Path newDirectoryStreamItem : newDirectoryStream) {
            Files.delete(newDirectoryStreamItem);
        }
    } catch (final Exception e) { // empty
    }
}

Modify the Path/String argument as needed. You can even convert between File and Path. Path is preferred for Java >= 8.

tb-
  • 1,240
  • 7
  • 10
6

I know I'm late to the party. However, for future reference, I wanted to contribute a java 8 stream solution that doesn't involve a loop.

It may not be pretty. I welcome suggestions to make it look better. However, it does the job:

Files.list(deleteDirectory).filter(p -> p.toString().contains("dailyReport_08")).forEach((p) -> {
    try {
        Files.deleteIfExists(p);
    } catch (Exception e) {
        e.printStackTrace();
    }
});

Alternatively, you can use Files.walk which will traverse the directory depth-first. That is, if the files are buried in different directories.

Lucas T
  • 3,011
  • 6
  • 29
  • 36
5

Use FileFilter like so:

File dir = new File(<path to dir>);
File[] toBeDeleted = dir.listFiles(new FileFilter() {
  boolean accept(File pathname) {
     return (pathname.getName().startsWith("dailyReport_08") && pathname.getName().endsWith(".txt"));
  } 

for (File f : toBeDeleted) {
   f.delete();
}
Erik
  • 2,013
  • 11
  • 17
  • This code would delete anything(including non `txt` files) starting with **dailyReport_08** probably would have also check the extension as well...but the code given BegemoT gives the perfect result..Thanks any way – Sangeet Menon Aug 30 '11 at 08:59
3

I agree with BegemoT.

However, just one optimization: If you need a simple FilenameFilter, there is a class in the Google packages. So, in this case you do not even have to create your own anonymous class.

import com.google.common.io.PatternFilenameFilter;

final File folder = ...
final File[] files = folder.listFiles(new PatternFilenameFilter("dailyReport_08.*\\.txt"));

// loop through the files
for ( final File file : files ) {
    if ( !file.delete() ) {
        System.err.println( "Can't remove " + file.getAbsolutePath() );
    }
}

Enjoy !

bvdb
  • 22,839
  • 10
  • 110
  • 123
3

There isn't a wildcard but you can implement a FilenameFilter and check the path with a startsWith("dailyReport_"). Then calling File.listFiles(filter) gives you an array of Files that you can loop through and call delete() on.

Jon Lin
  • 142,182
  • 29
  • 220
  • 220
1

or in scala

new java.io.File(<<pathStr>>).listFiles.filter(_.getName.endsWith(".txt")).foreach(_.delete())
1

You can't do it without a loop. But you can enhance this loop. First of all, ask you a question: "what's the problem with searching and removing in the loop?" If it's too slow for some reason, you can just run your loop in a separate thread, so that it will not affect your user interface.

Other advice - put your daily reports in a separate folder and then you will be able to remove this folder with all content.

Illarion Kovalchuk
  • 5,774
  • 8
  • 42
  • 54
  • A monthly folder agreed!!!....could have gone for a monthly folder but then certain requirements like merging files(of different months) could then become tedious....And looping as already stated large no of files... – Sangeet Menon Aug 30 '11 at 08:52
0

Have a look at Apache FileUtils which offers many handy file manipulations.

Adriaan Koster
  • 15,870
  • 5
  • 45
  • 60