Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's wrong with this Kotlin FileFilter?

I have the following FileFilter in my Kotlin Android app:

fileArray = fileDirectory.listFiles { file, filename ->
  file.length() > 0 && filename.matches(fileMatcherRegex)
}

It filters correctly on the filename matcher but it doesn't filter out files that have a length of 0. It I later iterate through fileArray and log the length of every file, I can sees lengths of 0.

Oddly, if I change the file.length() > 0 to, say, file.length() > 999999999999, it filters out all the files, so the length() element of the filter is being tested. It's just not producing results I understand.

What am I doing wrong?

I'm still getting my head around Kotlin lambdas, so I'm guessing my error relates to that.

thanks in advance

John

like image 666
John Avatar asked Sep 29 '18 03:09

John


1 Answers

The method listFiles expects a lambda with two parameters which is based on the SAM conversion from this method on the FilenameFilter interface:

/**
 * Tests if a specified file should be included in a file list.
 *
 * @param   dir    the directory in which the file was found.
 * @param   name   the name of the file.
 * @return  <code>true</code> if and only if the name should be
 * included in the file list; <code>false</code> otherwise.
 */
boolean accept(File dir, String name);

The first parameter is the DIRECTORY containing the file, not the file itself. Only the second parameter represents the file within the directory. So your file.length() is checking fileDirectory.length() instead of the file's length.

In effect read your original code as:

val fileArray = fileDirectory.listFiles { directory, filename ->
  directory.length() > 0 && filename.matches(fileMatcherRegex)
}

And you can see now that it is incorrect logic.

If you use a single parameter to your lambda then you are specifying one based on the SAM conversion from the FileFilter interface which is:

/**
 * Tests whether or not the specified abstract pathname should be
 * included in a pathname list.
 *
 * @param  pathname  The abstract pathname to be tested
 * @return  <code>true</code> if and only if <code>pathname</code>
 *          should be included
 */
boolean accept(File pathname);

And this is the correct one, where you are asking questions about the file and not the containing directory. Your code would then be:

val fileArray = fileDirectory.listFiles { file ->
  file.length() > 0 && file.name.matches(fileMatcherRegex) 
}
like image 179
2 revs, 2 users 99% Avatar answered Nov 14 '22 09:11

2 revs, 2 users 99%