Case sensitive file extension and existence checking - java

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;
}
}

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

How to get the file names present in a particular location mentioned

Can any one tell me how can I get the file names present in the particular location say
E:/abc_RESPONSE/Response_.
I tried to use The
java.io.File.getName()
method which returns the last name of the pathname's name sequence, that means the name of the file or directory denoted by this abstract path name is returned. But I need all the file names present in that particular location.
String name = (String)(new File("E:/abc_RESPONSE/Response_").getName());
I am using the above code please help to implement this.
Try this..
public void listFiles(String directoryName){
File directory = new File(directoryName);
//get all the files from a directory
File[] fList = directory.listFiles();
for (File file : fList){
if (file.isFile()){
System.out.println(file.getName());
}
}
}
try this
String[] names = new File("E:/abc_RESPONSE/Response_").list();

Why file.delete() do not remove the resource from disk?

My problem is, I need to delete all the files i.e. first, second, third. But as per below code only third file is getting deleted from path, not first and second. How to remove all files?
ArrayList<File> filesToAdd = new ArrayList<File>();
filesToAdd.add(first);
filesToAdd.add(second);
filesToAdd.add(third);
for (File file : filesToAdd) {
if(file!=null && file.isFile()){
file.delete();
}
}
when I run the app with debugger, if returns true for all files.
And I can't pass file.delete(path) because path is String.
The code you have try to delete files. There are few reasons why File.delete()
you don't have correct permissions to delete
the file the file represents a directory and the directory is not empty
the file is locked by another process, (or even by the same process in say an unclosed FileOutputStream)
the file doesn't exist
The method delete() return a boolean value that inform you about the state.
for (File file : filesToAdd) {
if(file!=null && file.isFile()){
if(file.delete() == false) {
//Add code what should happen
}
}
}
Note that your code is obsolete and use API from Java 6.
If it is possible switch to latest version 8, then you can
List<Path> paths = new ArrayList<>();
paths.add(first);
paths.add(second);
paths.add(third);
for (Path path : paths) {
if(Files.isRegularFile(path)) {
Files.delete(path);
}
}
The change is that Files.delete(path) will throw an exception that will tell you why you can not delete it.

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

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.

Java: renameTo() function failing

Java
The code below was written to read all files in, and send the data to another method (setOutput()), and then call a method to rename the last read file to another directory, and then delete the original. Everything seems to work up until the smdrCleanup() method is called. The renameTo() is failing.
From what I understand, if a FileReader is wrapped in a BufferedReader, I only need to call BufferedReader.close() to release the last read file... which I am doing here.
I have also seen where if the file were still "open", being scanned by anti-virus programs, or otherwise locked by a process, the renameTo() function would fail. I have used Process Explorer to review what may have it locked, and I don't see anything locking it.
I have my method setup to throw any kind of IOExceptions, but I am not getting any exceptions. Everything runs, but the console merely says that the file was not copied.
I am running Eclipse Helios Release 2, Windows 7 Ultimate, local administrator, UAC disabled.
Any help would be greatly appreciated.
public void smdrReader(String path, String oldPath) throws IOException
{
output = null; //nullify the value of output to avoid duplicate data
File folder = new File(path); //setting the directory for raw data files
File[] listOfFiles = folder.listFiles(); //array of files within the folder/directory
//For loop to iterate through the available files, open, & read contents to String Buffer.
for (int i = 0; i < listOfFiles.length; i++)
{
if (listOfFiles[i].isFile()) //verifying next entry in array is a file
{
File fileName = new File(listOfFiles[i].getName());//getting file name from array iteration
StringBuffer fileData = new StringBuffer(2048);//establishing StringBuffer for reading file contents into
BufferedReader reader = new BufferedReader(new FileReader(path + fileName));//reader to actually access/read file
String readData = String.valueOf(reader);//String variable being set to value of the reader
fileData.append(readData);//appending data from String variable into StringBuffer variable
setOutput(fileData);//setting the value of "output" to the value of StringBuffer
fileData.delete(0, i);
reader.close();//closing the reader (closing the file)
smdrCleanup(oldPath,fileName.toString());//calling method to move processed file and delete original
}
}
}
//method to rename input file into another directory and delete the original file to avoid duplicate processing
public void smdrCleanup(String oldPathPassed, String fileNamePassed) throws IOException
{
File oldFile = new File(oldPathPassed);//establishing File object for path to processed folder
File fileName = new File(fileNamePassed);//establishing File object for the fileName to rename/delete
String oldFilePath = oldFile.toString();
boolean success = fileName.renameTo(new File(oldFilePath + "\\" + fileName + ".old"));//attempting to rename file
if (!success) //checking the success of the file rename operation
{
System.out.println("The File Was NOT Successfully Moved!");//reporting error if the file cannot be renamed
}
else
{
fileName.delete();//deleting the file if it was successfully renamed
}
}
oldFile.toString(); returns the full path of the file including its file name, so if your old file path is c:\path\to\file.txt, oldFilePath + "\\" + fileName + ".old" will be c:\path\to\file.txt\file.txt.old.
Since there is no folder c:\path\to\file.txt, it fails. change it to
boolean success = fileName.renameTo(new File(oldFilePath + ".old"));
And you should be good to go.
File.renameTo can fail for any number of reasons:
Many aspects of the behavior of this
method are inherently
platform-dependent: The rename
operation might not be able to move a
file from one filesystem to another,
it might not be atomic, and it might
not succeed if a file with the
destination abstract pathname already
exists. The return value should always
be checked to make sure that the
rename operation was successful.
But there's not much feedback on why it fails. Before calling renameTo, verify that the file you're moving exists, and the parent directory you are moving it to also exists, and canWrite(). Are these on the same disk volume? If not, it might fail.
*EDIT: Code sample added *
Try something like the following. Modifications:
Accepts File objects instead of Strings
Uses 2-arg File constructor to create a child File object in a parent directory
Better error checking
This might give you some clues into what is failing.
public void smdrCleanup(File oldPathPassed, File fileNamePassed) throws IOException {
if (!oldPathPassed.exists() || !oldPathPassed.isDirectory() || !oldPathPassed.canWrite() ) throw new IOException("Dest is not a writable directory: " + oldPathPassed);
if (!fileNamePassed.exists()) throw new IOException("File does not exist: " + fileNamePassed);
final File dest = new File(oldPathPassed, fileNamePassed + ".old");
if (dest.exists()) throw new IOException("File already exists: " + dest);
boolean success = (fileNamePassed).renameTo(dest);//attempting to rename file
if (!success) //checking the success of the file rename operation
{
throw new IOException("The File Was NOT Successfully Moved!");
} else {
// file was successfully renamed, no need to delete
}
}

Categories

Resources