I am developing an Android App. I have the below code to write a list of all files starting with XLR in a particular folder:
private List<File> getListFiles(File parentDir) {
ArrayList<File> inFiles = new ArrayList<File>();
File[] files = parentDir.listFiles();
for (File file : files) {
try {
if ((file.exists()) && (file != null)) {
if (file.isDirectory()) {
inFiles.addAll(getListFiles(file));
} else {
if (file.getName().startsWith("XLR")) {
inFiles.add(file);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
return inFiles;
}
On Android 10 and 11 it seems to be a problem. For Android 10 I have legacy storage enabled and Android 11 I have got access to all files. So the issue is not file access.
The folder itself might not be in my app's folder, hence the need to be able to list out files
I know that there is an extensive page here on NPE's and I have tried my best to follow the advice there (I am checking that files exist and are not null), but still to no avail.
I feel that there's probably something so stupid, that a more experienced programmer would probably pick out in 2 seconds...
This problem would be easily solved just reading the documentation of the actual File package.
Documentation on the method File::listFiles:
An array of abstract pathnames denoting the files and directories in the directory denoted by this abstract pathname. The array will be empty if the directory is empty. Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs.
As you can see, that method can actually return null and not only an empty array, so you should check that the value isn't null before even trying to iterate over it.
I need to get a list of files but ignore a particular subdirectory. For example here is a sample structure.
Content
->1
-->file_a.mp4
-->file_b.mp4
->2
-->file_c.mp4
-->file_d.mp4
->Bonus
-->1
--->file_e.mp4
--->file_f.mp4
I need to be able to get a list of files/directories that excludes the bonus directory.
I also need to separate list the files for the bonus directory, but I think that can be easily solved by using the normal method.
How do I perform a list files, but ignore a directory?
Here is my sample code that is going to return everything
final List<Boxset> boxsets = getCloudBoxsetsWithTrackData(context);
final File[] boxsetFiles = dir.listFiles();
if (boxsetFiles != null)
{
for (File subDir : boxsetFiles)
{
if (subDir.isDirectory())
{
for (Boxset boxset : boxsets)
{
if (subDir.getName().equalsIgnoreCase(String.valueOf(boxset.persistentId)))
{
DBHandler.getInstance(context).moveBoxsetToDeviceList(boxset);
DownloadLibrarian.getInstance(context).stopDownload(boxset);
}
}
}
}
}
You can make use of FileFilter to obtain a list of sub-directories that doesn't include Bonus
File[] nonBonusDirs = dir.listFiles(new FileFilter() {
#Override public boolean accept(File file) {
return file.isDirectory() && !file.getName().equalsIgnoreCase("bonus");
}
});
You can then obtain a list of all files not in the Bonus directory
List<File> filesNotInBonusDir = new ArrayList<>();
for (File directory : nonBonusDirs) {
filesNotInBonusDir.addAll(Arrays.asList(directory.listFiles()));
}
Though of course these shenanigans are much nicer in Kotlin thanks to flatMap ;)
val filesNotInBonusDir: List<File> = dir.listFiles()
.filter { it.isDirectory && !it.name.equals("bonus", ignoreCase = true) }
.flatMap { it.listFiles().toList() }
Is there a Java equivalent for System.IO.Path.Combine() in C#/.NET? Or any code to accomplish this?
This static method combines one or more strings into a path.
Rather than keeping everything string-based, you should use a class which is designed to represent a file system path.
If you're using Java 7 or Java 8, you should strongly consider using java.nio.file.Path; Path.resolve can be used to combine one path with another, or with a string. The Paths helper class is useful too. For example:
Path path = Paths.get("foo", "bar", "baz.txt");
If you need to cater for pre-Java-7 environments, you can use java.io.File, like this:
File baseDirectory = new File("foo");
File subDirectory = new File(baseDirectory, "bar");
File fileInDirectory = new File(subDirectory, "baz.txt");
If you want it back as a string later, you can call getPath(). Indeed, if you really wanted to mimic Path.Combine, you could just write something like:
public static String combine(String path1, String path2)
{
File file1 = new File(path1);
File file2 = new File(file1, path2);
return file2.getPath();
}
In Java 7, you should use resolve:
Path newPath = path.resolve(childPath);
While the NIO2 Path class may seem a bit redundant to File with an unnecessarily different API, it is in fact subtly more elegant and robust.
Note that Paths.get() (as suggested by someone else) doesn't have an overload taking a Path, and doing Paths.get(path.toString(), childPath) is NOT the same thing as resolve(). From the Paths.get() docs:
Note that while this method is very convenient, using it will imply an assumed reference to the default FileSystem and limit the utility of the calling code. Hence it should not be used in library code intended for flexible reuse. A more flexible alternative is to use an existing Path instance as an anchor, such as:
Path dir = ...
Path path = dir.resolve("file");
The sister function to resolve is the excellent relativize:
Path childPath = path.relativize(newPath);
The main answer is to use File objects. However Commons IO does have a class FilenameUtils that can do this kind of thing, such as the concat() method.
platform independent approach (uses File.separator, ie will works depends on operation system where code is running:
java.nio.file.Paths.get(".", "path", "to", "file.txt")
// relative unix path: ./path/to/file.txt
// relative windows path: .\path\to\filee.txt
java.nio.file.Paths.get("/", "path", "to", "file.txt")
// absolute unix path: /path/to/filee.txt
// windows network drive path: \\path\to\file.txt
java.nio.file.Paths.get("C:", "path", "to", "file.txt")
// absolute windows path: C:\path\to\file.txt
I know its a long time since Jon's original answer, but I had a similar requirement to the OP.
By way of extending Jon's solution I came up with the following, which will take one or more path segments takes as many path segments that you can throw at it.
Usage
Path.combine("/Users/beardtwizzle/");
Path.combine("/", "Users", "beardtwizzle");
Path.combine(new String[] { "/", "Users", "beardtwizzle", "arrayUsage" });
Code here for others with a similar problem
public class Path {
public static String combine(String... paths)
{
File file = new File(paths[0]);
for (int i = 1; i < paths.length ; i++) {
file = new File(file, paths[i]);
}
return file.getPath();
}
}
To enhance JodaStephen's answer, Apache Commons IO has FilenameUtils which does this. Example (on Linux):
assert org.apache.commons.io.FilenameUtils.concat("/home/bob", "work\\stuff.log") == "/home/bob/work/stuff.log"
It's platform independent and will produce whatever separators your system needs.
Late to the party perhaps, but I wanted to share my take on this. I prefer not to pull in entire libraries for something like this. Instead, I'm using a Builder pattern and allow conveniently chained append(more) calls. It even allows mixing File and String, and can easily be extended to support Path as well. Furthermore, it automatically handles the different path separators correctly on both Linux, Macintosh, etc.
public class Files {
public static class PathBuilder {
private File file;
private PathBuilder ( File root ) {
file = root;
}
private PathBuilder ( String root ) {
file = new File(root);
}
public PathBuilder append ( File more ) {
file = new File(file, more.getPath()) );
return this;
}
public PathBuilder append ( String more ) {
file = new File(file, more);
return this;
}
public File buildFile () {
return file;
}
}
public static PathBuilder buildPath ( File root ) {
return new PathBuilder(root);
}
public static PathBuilder buildPath ( String root ) {
return new PathBuilder(root);
}
}
Example of usage:
File root = File.listRoots()[0];
String hello = "hello";
String world = "world";
String filename = "warez.lha";
File file = Files.buildPath(root).append(hello).append(world)
.append(filename).buildFile();
String absolute = file.getAbsolutePath();
The resulting absolute will contain something like:
/hello/world/warez.lha
or maybe even:
A:\hello\world\warez.lha
If you do not need more than strings, you can use com.google.common.io.Files
Files.simplifyPath("some/prefix/with//extra///slashes" + "file//name")
to get
"some/prefix/with/extra/slashes/file/name"
Here's a solution which handles multiple path parts and edge conditions:
public static String combinePaths(String ... paths)
{
if ( paths.length == 0)
{
return "";
}
File combined = new File(paths[0]);
int i = 1;
while ( i < paths.length)
{
combined = new File(combined, paths[i]);
++i;
}
return combined.getPath();
}
This also works in Java 8 :
Path file = Paths.get("Some path");
file = Paths.get(file + "Some other path");
This solution offers an interface for joining path fragments from a String[] array. It uses java.io.File.File(String parent, String child):
public static joinPaths(String[] fragments) {
String emptyPath = "";
return buildPath(emptyPath, fragments);
}
private static buildPath(String path, String[] fragments) {
if (path == null || path.isEmpty()) {
path = "";
}
if (fragments == null || fragments.length == 0) {
return "";
}
int pathCurrentSize = path.split("/").length;
int fragmentsLen = fragments.length;
if (pathCurrentSize <= fragmentsLen) {
String newPath = new File(path, fragments[pathCurrentSize - 1]).toString();
path = buildPath(newPath, fragments);
}
return path;
}
Then you can just do:
String[] fragments = {"dir", "anotherDir/", "/filename.txt"};
String path = joinPaths(fragments);
Returns:
"/dir/anotherDir/filename.txt"
Assuming all given paths are absolute paths. you can follow below snippets to merge these paths.
String baseURL = "\\\\host\\testdir\\";
String absoluteFilePath = "\\\\host\\testdir\\Test.txt";;
String mergedPath = Paths.get(baseURL, absoluteFilePath.replaceAll(Matcher.quoteReplacement(baseURL), "")).toString();
output path is \\host\testdir\Test.txt.
I want to make an array of specific types of files with .txt that are found in all android folders.
I am bit off I need to loop through all folders then create a list out of all the items found with the file name of ".txt".
My question is what method do I need to start from the top of all the folders? Also I need a method to open a specific folder(So I can loop through the FileNameFilter method).
Also I don't mind any recommendation on how to do this kind of method.
public String getFile(int position){
File root = Environment.getExternalStorageDirectory();//This is incorrect it just goes to it's current environment it's folder found for this application.
FilenameFilter filter = new FilenameFilter() {
public boolean accept(File dir, String filename) {
// TODO Auto-generated method stub
return !filename.endsWith(".txt");
}
};
ArrayList<File> items = new ArrayList<File>(Arrays.asList(root.listFiles(filter)));
String returned = items.get(position).toString();
return returned;
You need a recursive method that will loop through a folder and, for each child : if the child is a folder, call itself with the child as parameter. If the child is a file, check its name and add it if needed.
You can do something like
public void findAllFilesWithExtension( File dir, String extension, List<File> listFiles ) {
List<File> listChildren = Arrays.asList(dir.listFiles());
for( File child : listChildren ) {
if( child.isDirectory() ) {
findAllFilesWithExtension( child, extension, listFiles );
} else if( child.getName().endsWith( extension ) ) {
listFiles.add( child );
} //else
} //for
}//met
And call it first on your root directory.
I am writing a app which can programatically clear application cache of all the third party apps installed on the device. Following is the code snippet for Android 2.2
public static void trimCache(Context myAppctx) {
Context context = myAppctx.createPackageContext("com.thirdparty.game",
Context.CONTEXT_INCLUDE_CO|Context.CONTEXT_IGNORE_SECURITY);
File cachDir = context.getCacheDir();
Log.v("Trim", "dir " + cachDir.getPath());
if (cachDir!= null && cachDir.isDirectory()) {
Log.v("Trim", "can read " + cachDir.canRead());
String[] fileNames = cachDir.list();
//Iterate for the fileName and delete
}
}
My manifest has following permissions:
android.permission.CLEAR_APP_CACHE
android.permission.DELETE_CACHE_FILES
Now the problem is that the name of the cache directory is printed but the list of files cachDir.list() always returns null. I am not able to delete the cache directory since the file list is always null.
Is there any other way to clear the application cache?
"android.permission.CLEAR_APP_CACHE" android.permission.DELETE_CACHE_FILES"
Ordinary SDK applications cannot hold the DELETE_CACHE_FILES permission. While you can hold CLEAR_APP_CACHE, there is nothing in the Android SDK that allows you to clear an app's cache.
Is there any other way to clear the application cache?
You are welcome to clear your own cache by deleting the files in that cache.
Check out android.content.pm.PackageManager.clearApplicationUserData: http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.3_r1/android/content/pm/PackageManager.java/
The other hidden methods in that class might be useful, too.
In case you've never used hidden methods before, you can access hidden methods using Java reflection.
poate iti merge asta
static int clearCacheFolder(final File dir, final int numDays) {
int deletedFiles = 0;
if (dir!= null && dir.isDirectory()) {
try {
for (File child:dir.listFiles()) {
//first delete subdirectories recursively
if (child.isDirectory()) {
deletedFiles += clearCacheFolder(child, numDays);
}
//then delete the files and subdirectories in this dir
//only empty directories can be deleted, so subdirs have been done first
if (child.lastModified() < new Date().getTime() - numDays * DateUtils.DAY_IN_MILLIS) {
if (child.delete()) {
deletedFiles++;
}
}
}
}
catch(Exception e) {
Log.e("ATTENTION!", String.format("Failed to clean the cache, error %s", e.getMessage()));
}
}
return deletedFiles;
}
public static void clearCache(final Context context, final int numDays) {
Log.i("ADVL", String.format("Starting cache prune, deleting files older than %d days", numDays));
int numDeletedFiles = clearCacheFolder(context.getCacheDir(), numDays);
Log.i("ADVL", String.format("Cache pruning completed, %d files deleted", numDeletedFiles));
}
I'm not sure how appropriate this is in terms of convention, but this works so far for me in my Global Application class:
File[] files = cacheDir.listFiles();
for (File file : files){
file.delete();
}
Of course, this doesn't address nested directories, which might be done with a recursive function like this (not tested extensively with subdirectories):
deleteFiles(cacheDir);
private void deleteFiles(File dir){
if (dir != null){
if (dir.listFiles() != null && dir.listFiles().length > 0){
// RECURSIVELY DELETE FILES IN DIRECTORY
for (File file : dir.listFiles()){
deleteFiles(file);
}
} else {
// JUST DELETE FILE
dir.delete();
}
}
}
I didn't use File.isDirectory because it was unreliable in my testing.