Get file case-sensitive name, with case-insensitive spelling - java

I am making an application where the user picks a file from:
FilePicker.PickFile(filename)
where filename is a string.
In the method, it will translate into:
File file = new File(filename);
and nothing is wrong with that. Next, I do,
if(file.exists()){
System.out.println(file.getName());
}
else{
System.out.println("Fail.");
}
and this is where the problem begins. I want to get the name of the file, say "HELLO.txt," but if filename is "hello.txt," it still passes the file.exists() check, and file.getName() returns as "hello.txt," not "HELLO.txt". Is there a way, to return file.getName() as the case-sensitive version as "HELLO.txt?" Thanks!
An example:
HELLO.txt is the real file
FilePicker.PickFile("hello.txt");
OUTPUT:
hello.txt

When you are using Windows, which is case preserving (FAT32/NTFS/..), you can use file.getCanonicalFile().getName() to get the canonical name of the selected file.
When you are using Linux or Android and you want to select a file based on a file name that does not necessarily match case, iterate through all files in the file's directory (file.getParent()), and pick the one that .equalsIgnoreCase the filename. Or see Case-insensitive File.equals on case-sensitive file system

/**
* Maps lower case strings to their case insensitive File
*/
private static final Map<String, File> insensitiveFileHandlerCache = new HashMap<String, File>();
/**
* Case insensitive file handler. Cannot return <code>null</code>
*/
public static File newFile(String path) {
if (path == null)
return new File(path);
path = path.toLowerCase();
// First see if it is cached
if (insensitiveFileHandlerCache.containsKey(path)) {
return insensitiveFileHandlerCache.get(path);
} else {
// If it is not cached, cache it (the path is lower case)
File file = new File(path);
insensitiveFileHandlerCache.put(path, file);
// If the file does not exist, look for the real path
if (!file.exists()) {
// get the directory
String parentPath = file.getParent();
if (parentPath == null) {
// No parent directory? -> Just return the file since we can't find the real path
return file;
}
// Find the real path of the parent directory recursively
File dir = Util.newFile(parentPath);
File[] files = dir.listFiles();
if (files == null) {
// If it is not a directory
insensitiveFileHandlerCache.put(path, file);
return file;
}
// Loop through the directory and put everything you find into the cache
for (File otherFile : files) {
// the path of our file will be updated at this point
insensitiveFileHandlerCache.put(otherFile.getPath().toLowerCase(), otherFile);
}
// if you found what was needed, return it
if (insensitiveFileHandlerCache.containsKey(path)) {
return insensitiveFileHandlerCache.get(path);
}
}
// Did not find it? Return the file with the original path
return file;
}
}
Use
File file = newFile(path);
instead of
File file = new File(path);
It's backed by a cache so it shouldn't be too slow. Did a few test runs and it seems to work. It recursively checks the the parent directories to see if they do have the correct letter cases. Then it lists for each directory all files and caches their correct letter casing. In the end it checks if the file with the path has been found and returns the file with the case sensitive path.

Looks like in Java 7 and above on Windows, you can use Path#toRealPath(NOFOLLOW_LINKS) and it would be more correct than getCanonicalFile() in the presence of symlinks.

Related

How to check whether a file exists in (Internal/External storage) by using file name?

I have been working on a project where I will get a filename from API and have to check whether the file is present in the device and play it.
I am getting Screenshot.jpg as filename from API and under the same name a file is present in my storage.
But when I used the piece of code, I have been returned false. I have checked with other codes also.
public boolean isFilePresent(String fileName) {
String path = this.getFilesDir().getAbsolutePath() + "/" + fileName;
File file = new File(path);
return file.exists();
}
where am I going wrong? Any help would be greatly appreciated!
Probably, what you do wrong is using this.getFilesDir().
Instead, use Environment.getExternalStorageDirectory().toString() for example, it's all dependant on where your file is.
Like I said before, debug it yourself, print (or present a toast) with the 'expected' file path, then verify it doesn't exist
Try something like that :
public boolean isFilePresent(Context context, String fileName) {
File dirFiles = context.getFilesDir();
File[] filesArray = dirFiles.listFiles();
for (File file : filesArray) {
if (file.getName().equals(fileName)) {
return true;
}
}
return false;
}
Use Environment.getExternalStorageDirectory() this is how you get the files directory
then you will add your files path after it, so you should do something like this
if(!new File(Environment.getExternalStorageDirectory().toString()+"/myFolder/"+"myFile").exist())
{
// file is not exist
}
remember to check the runtime permission because it's a special permission

Scanning sub folder

I am trying to search files from sd card so i can delete multiple and duplicate files.``
private List<String> searchForFileNameContainingSubstring(String substring)
{
path = Environment.getExternalStorageDirectory().getPath() + "/";
//This is assuming you pass in the substring from input.
File file = new File(path); //Change this to the directory you want to search in.
List<String> filesContainingSubstring = new ArrayList<String>();
if (file.exists() && file.isDirectory())
{
String[] files = file.list(); //get the files in String format.
for (String fileName : files)
{
if (fileName.contains(substring))
filesContainingSubstring.add(fileName);
}
}
for (String fileName : filesContainingSubstring)
{
System.out.println(fileName); //or do other operation
}
return filesContainingSubstring; //return the list of filenames containing substring.
}
How can i scan other sub folders from sdcard/ directories
It only shows results from sdcard directories
You can use Apache Common's FileUtils.listFiles method.
You can search recursively throughout a folder by setting the third parameter as true.
Also, you can target specific file extensions by passing in the second argument a String array as seen below. If you want to target any extensions pass null.
Note: the extensions names do not include '.' it's "jpg" and not ".jpg"
String[] extensions = {"png","jpg"};
Collection images = FileUtils.listFiles(new File("dirPath"),extensions, true);
for (Object obj : images){
File file = (File) obj;
// your code logic
}

how to check if the given local path is accessible for write in java

I want to check below
A) Path type: local:C:\program files\cts\ABCD_PP\dd\
1) check if the path exists
2) if path exists then check if the path is writable(means should be able to place a file on that path).
also
B) shared path:\\mdyptcmedia101\transmit\in\
will it be same procedure as local file path verificaion or different
using Jdk 1.6 in spring project.
Please help.
RTM: File.isDirectory(), File.canWrite()
File file = new File("...");
boolean canWrite = file.canWrite();
boolean isDirectory = file.isDirectory();
Both detailed in the javadoc
This is rather simple.
String path = "..."; // Whatever the path may be
File file = new File(path);
if (file.isDirectory()) {
// The path exists and it is a directory
if (file.canWrite() {
// The directory is writable
} else {
// The directory is not writable
}
} else {
// The path is not a directory, or it does not even exist
}
File I/O - Checking a File or Directory
Path path = ...;
if (Files.exists(path))
/* the path exists */;
if (Files.isDirectory(path))
/* the path exists and is a directory */;
if (Files.isWritable(path))
/* the path is writable */;

Case sensitive file extension and existence checking

I need to check whether or not a file exists. Which can be accomplished by File#exists() method. But this existence checking is case sensitive. I mean if I have a file name some_image_file.jpg in code but if physically the file is some_image_file.JPG then this method says that the file doesn't exists. How can I check the file existence with case insensitivity to the extension and get the actual file name?
In my scenario, I have a excel file. Each row contains metadata for files and the filename. In some cases I have only the filename or other cases I can have full path. I am denoting a row as a document.
These files are placed in the server. My job is to
Read the excel file row by row and list all the documents.
Take out the filename or filepath.
Create the full path of the file.
Check if the file exists or not.
Validate other metadata/information provided in the document.
Upload the file.
My application throws exception in case the file doesn't exists or if some metadata are invalid.
The excel file is written by the customer and they wrote some file name wrong, I mean if the file physically have the extension in lower case, they have written the extension in upper case, also the converse is true.
I am running the application in unix server.
As the file extensions are not matching so the File#exists() is giving false and eventually my code is throwing exception.
The folders where the files are placed can have 30000 or more files.
What I want is
To take the full path of the file.
Check if the file exists or not.
If it does not exists then
Check the file existence by converting the case of the extension.
If it doesn't exist after the case conversion then throw exception.
If it exists, then return the actual file name or file path.
If the file name has file extension something like .Jpg, don't know what to do! Should I check it by permuting it by changing the case?
You could get the file names in a folder with
File.list()
and check names by means of
equalsIgnoreCase()
Or try http://commons.apache.org/io/
and use
FileNameUtils.directoryContains(final String canonicalParent, final String canonicalChild)
This way I had solved the problem:
public String getActualFilePath() {
File givenFile = new File(filePath);
File directory = givenFile.getParentFile();
if(directory == null || !directory.isDirectory()) {
return filePath;
}
File[] files = directory.listFiles();
Map<String, String> fileMap = new HashMap<String, String>();
for(File file : files) {
if(file.isDirectory()){
continue;
}
String absolutePath = file.getAbsolutePath();
fileMap.put(absolutePath, StringUtils.upperCase(absolutePath));
}
int noOfOcc = 0;
String actualFilePath = "";
for(Entry<String, String> entry : fileMap.entrySet()) {
if(filePath.toUpperCase().equals(entry.getValue())) {
actualFilePath = entry.getKey();
noOfOcc++;
}
}
if(noOfOcc == 1) {
return actualFilePath;
}
return filePath;
}
Here filePath is the full path to the file.
The canonical name returns the name with case sensitive. If it returns a different string than the name of the file you are looking for, the file exists with a different case.
So, test if the file exists or if its canonical name is different
public static boolean fileExistsCaseInsensitive(String path) {
try {
File file = new File(path);
return file.exists() || !file.getCanonicalFile().getName().equals(file.getName());
} catch (IOException e) {
return false;
}
}

Cannot delete temp folder (sometimes)

When I start my application I create a temp folder:
public static File createTempDir(String name) throws IOException {
File tempDir = File.createTempFile(name, "");
if (!(tempDir.delete())) {
throw new IOException("could not delete" + tempDir.getAbsolutePath());
}
if (!(tempDir.mkdir())) {
throw new IOException("could not create" + tempDir.getAbsolutePath());
}
tempDir.deleteOnExit();
return tempDir;
}
During a session a user might load a file. As a result the old temp dir is deleted and a new is created based on the ID of the file loaded.
During load where the old temp dir is deleted I sometimes get a:
java.io.IOException: Unable to delete file:
Here is how the old temp folder is deleted:
public void cleanup(String tmpPath) {
File tmpFolder = new File(tmpPath);
if (tmpFolder != null && tmpFolder.isDirectory()) {
try {
FileUtils.deleteDirectory(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
where FileUtils is: org.apache.commons.io.FileUtils. Typically the content of the temp folder is:
mytempfolder_uuid
|-> mysubfolder
|-> myImage.jpg
And the error is:
java.io.IOException: Unable to delete file: C:\Users\xxx\AppData\Local\Temp\mytempfolder_uuid\mysubfolder\myImage.jpg
I have tried to debug the application and before the delete operation is executed verified that the above image is actually located in the specified folder.
The nasty thing is that it only happens sometimes. I have made sure not to have the folder/files in the temp folder open in any other applications. Any ideas/suggestions?
You cannot delete files which are open and you can't delete a directory which contains a file. You have to ensure all files in the directory are closed.
I'd suggest you use the Guava library. It has a method Files.createTempDir() that does exactly what you seem to need:
Atomically creates a new directory somewhere beneath the system's
temporary directory (as defined by the java.io.tmpdir system
property), and returns its name. Use this method instead of
File.createTempFile(String, String) when you wish to create a
directory, not a regular file. A common pitfall is to call
createTempFile, delete the file and create a directory in its place,
but this leads a race condition which can be exploited to create
security vulnerabilities, especially when executable files are to be
written into the directory. This method assumes that the temporary
volume is writable, has free inodes and free blocks, and that it will
not be called thousands of times per second.
try deleting the files in the temp folder before deleting it. Try somethng like
private boolean deleteFolder(File path) {
if (path.exists()) {
File[] files = path.listFiles();
for (File f : files) {
if (f.isDirectory()) {
deleteFolder(f);
} else {
f.delete();
}
}
}
return path.delete();
}
also using deleteOnExit is not a very good idea...
cheers!
public static boolean deleteDir(String path)
{
java.io.File dir = new java.io.File(path);
if (dir.isDirectory())
{
String[] filesList = dir.list();
for(String s : filesList)
{
boolean success = new java.io.File(dir, s).delete();
if(!success)
{
return false;
}
}
}
return dir.delete();
}
and then you can use it like: deleteDir("C:\\MyFolder\\subFolder\\")

Categories

Resources