Why am I able to delete a file in my Java code despite the Tomcat user not having the deletion permissions?
My server is running the following code, which deletes and recreates a file if it exists:
File fileCSV = new File(filePath);
try {
if (fileCSV.exists()) {
fileCSV.delete();
}
fileCSV.createNewFile();
} catch (IOException ex) {
throw new FooImportException("Error creating new file");
}
It is able to delete the file despite the user used by the server not having deletion permissions - only read and write permissions.
I am certain that these are the relevant permissions, as the code fails on the file creation line without the "Create files / Write data" permissions. However, it does not fail on the deletion line when lacking the "Delete" permission. What might be the reasoning for this?
According to the JavaDocs for File#delete
public boolean delete() Deletes the file or directory denoted by
this abstract pathname. If this pathname denotes a directory, then the
directory must be empty in order to be deleted. Note that the Files
class defines the delete method to throw an IOException when a file
cannot be deleted. This is useful for error reporting and to diagnose
why a file cannot be deleted.
Returns: true if and only if the file or directory is successfully
deleted; false otherwise Throws: SecurityException - If a
security manager exists and its
SecurityManager.checkDelete(java.lang.String) method denies delete
access to the file
So, File#delete does not actually throw an Exception when the file can't be deleted, but instead returns a boolean based on the success of the operation.
If the Exception is important to you, then you should use Files#delete instead.
It's important to note - this only solves the question of "why does it not fail" based on the available code, not the question of "would it fail" based on the available file permissions
Related
I basically want to make a watch service (or something like it) that checks if a file has been closed and instantly remove that file if it did close(finished executing).
How I can achieve this? please give me a cmd commands or some code(i prefer Java).
Ok, this should not be hard to do, if you google a bit you find a Java-File Method called file.canWrite() which basically returns if a file is locked by an other program or so.
So codewise what you could do is something like this.
boolean isDeleted = false;
File f = new File (// Put your file here);
while (!isDeleted) {
if (f.canWrite()) {
f.delete();
isDeleted = true;
} else {
try {
Thread.sleep(10); // Throws Exception you need to catch somewhere...
} catch (Exception e) {}
}
}
This code you need to include into some Java-Program. I added a simple Thread.sleep(10) that your PC does not have to check aaaaaalllllllll the time.
See Check if a file is locked in Java
Other possibility would be trying to rename the file with file.renameTo("some_path.txt"); as this method also returns a boolean whether it was successfull! Just note that you then need to update the file again before removing it.
Last possibility I see is pretty similar to the second one. You try to delete the file by calling file.delete(); If the file still exists you know it was not successful and loop because of that.
I assume you mean when the file is not open in another program, and you cannot make changes to that other program? (If you are talking about your own program opening the file, this is much easier.)
On Windows, it is not very easy to tell which program has a file open. Take a look at https://superuser.com/questions/117902/find-out-which-process-is-locking-a-file-or-folder-in-windows for some options. I like the handle tool for this, but it has to run as Administrator, which may be a problem. You can try renaming or writing to the file, as suggested at Check if a file is locked in Java
Once you have a script that determines whether the file is open to your satisfaction, it should be fairly straightforward to write a script which loops while testing if the file is open and then deletes file.
I decided to post a new question on this since none of the existing posts lead to me a solution. Mine is a Spring Boot application and here is the service:
public String fetchPrediction(MultipartFile file) throws IOException, InterruptedException {
File convFile = new File( System.getProperty("user.dir")+"/"+file.getOriginalFilename());
convFile.setWritable(true);
file.transferTo(convFile);
INDArray array = new CustomerLossPrediction().generateOutput(convFile);
Files.delete(Paths.get(convFile.getPath()));
return array.toString();
}
File deletion isn't happening and it gets stored at user home directory:
Found that the file is being used by the Java process. How can I delete this file once execution is completed? Is there a better approach here rather than writing to a file? Some of you would bring up writing to OutputStream here, but note that I need to work with MultipartFile in order to have file upload functionality.
I don't know if that's possible but I think you can rename the file to a randomly generated string then afterwards lock, read, unlock then delete the renamed file. In theory, another program could guess the filename and read the file just after it's unlocked but before it is deleted. But in practice, you'll probably be fine.
I want to delete one file and rename another file with the old file but I am not able to move this file as java is throwing java.nio.file.FileAlreadyExistsException Following is the code snippet I am using
static void swapData(String origFilePath, String tempFilePath) throws IOException{
Path tempPath = FileSystems.getDefault().getPath(tempFilePath);
Path origPath = FileSystems.getDefault().getPath(origFilePath);
try{
String origFileName = null;
File origFileRef = new File(origFilePath);
if(Files.exists(origPath)){
origFileName = origFileRef.getName();
Files.delete(origPath);
if(Files.exists(origPath))
throw new IOException("cannot able to delete original file");
}
if(origFileName != null)
Files.move(tempPath, tempPath.resolveSibling(origFileName), StandardCopyOption.REPLACE_EXISTING);
}catch(IOException e){
throw e;
}
}
Here is the exception I am recieving
on Files.move(tempPath, tempPath.resolveSibling(origFileName), StandardCopyOption.REPLACE_EXISTING);
Also when I see this file in windows explorer, its thumbnail is present but cannot able to open it. I am not able to understand why it is happening and If I am using REPLACE_EXISTING, why it is throwing FileAlreadyExistsException exception.
Also I edited the previous question as it is not clearly stated.
Please help.
Anuj
Check if you have another thread holding on to the same file resource while running Files.move or Files.copy. I had the same exception and file access symptom and was able to resolve it after serializing the file accesses.
Also, by using the REPLACE_EXISTING option when doing Files.copy or Files.move, you no longer need to code the multiple steps of deleting the original file and then renaming the tmp, although Files.move or Files.copy are not guaranteed atomic. There is a ATOMIC_MOVE option, however I don't like the implementation specific guarantee where IOException could be thrown if a file exists already as described by the javadoc.
ATOMIC_MOVE : The move is performed as an atomic file system operation and all other options are ignored. If the target file exists then it is implementation specific if the existing file is replaced or this method fails by throwing an IOException. If the move cannot be performed as an atomic file system operation then AtomicMoveNotSupportedException is thrown. This can arise, for example, when the target location is on a different FileStore and would require that the file be copied, or target location is associated with a different provider to this object.
I have eclipse plugin jface application.
A thread writes file via BufferedWriter.
After writing is done I close the buffer after that I try to rename the file.
But sometimes file is not renamed!
I tried to add some Thread.Sleep(BIG_NUMBER) between couple of retries this didn't help.
It looks like the file getting some kind of lock. (when I kill the jvm I can rename the file).
Is there something I can do?
OS: Windows XP, windows 7
JAVA version: 1.5
File.RenameTo() is platform dependent and relies on a few conditions to be met in order to succesfully rename a file, a better alternative is using
Path source = currentFile.toPath();
try {
Files.move(source, source.resolveSibling(formattedName));
} catch (IOException e) {
e.printStackTrace();
}
Read more here.
From the javadocs:
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.
Note that the Files class defines the move method to move or rename a file in a platform independent manner.
For the File.renameTo() to work,The file will need to be somehow writable by external applications.
You can also do something like below:
File o=new File("oldFile.txt");
File n=new File("newFile.txt");
n.delete();
o.renameTo(n);
n.delete() : We need to delete the file(new.txt) if exists.
o.rename(n) : so that the file(old.txt) is renamed as new.txt
How to find out why renameTo() failed?
Reliable File.renameTo() alternative on Windows?
http://www.bigsoft.co.uk/blog/index.php/2010/02/02/file-renameto-always-fails-on-windows
We have had issues under Windows 7 with UAC and unexpected file permissions. File#canWrite will return true even though any attempts to perform file I/O will fail.
Make sure the file you are trying to rename actually exists
Make sure that the location you are attempting to write the file (or rename the file) to is accessible. We write a simple text file to the location, check to see if it exists and that it's contents is correct (we're paranoid) before we attempt any further I/O.
This is working fine for me. Rename is done using two steps but don't forget to set permissions in manifest.xml with:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
public boolean RenameFile(String from, String to) {
to.replace(" ", ""); // clear all spaces within file name
File oldfile = new File(from);
File newfile = new File(to);
File tempfile = new File(to + ".tmp"); // add extension .tmp
oldfile.renameTo(tempfile);
return (tempfile.renameTo(newfile));
}
My small utility application asks the user for an output directory via a GUI file selector.
Then it creates a lot of files in this output directory after some processing.
I need to check if the application has write access so that it informs the user and does
not continue with the processing (which might take a long time)
My first attempt was the canWrite() method of java.io.File. But this does not work
since it deals with the directory entry itself and not its contents. I have seen at least
one instance of a Windows XP folder that can be renamed or deleted but no files may be created
in it (because of permissions). This is actually my testcase.
I finally settled with the following solution
//User places the input file in a directory and selects it from the GUI
//All output files will be created in the directory that contains the input file
File fileBrowse = chooser.getSelectedFile(); //chooser is a JFileChooser
File sample = new File(fileBrowse.getParent(),"empty.txt");
try
{
/*
* Create and delete a dummy file in order to check file permissions. Maybe
* there is a safer way for this check.
*/
sample.createNewFile();
sample.delete();
}
catch(IOException e)
{
//Error message shown to user. Operation is aborted
}
However this does not feel elegant to me since it just tries to actually create a file and checks if the operation succeeds.
I suspect that there must be a better way for this but all solutions I have found so far
with Security Managers and stuff deal with Java Applets and not standalone applications.
Am I missing something?
What is the recommended way of checking for file access inside a directory before
actually writing the files?
I am using Java 5.
You could check the file permissions, make sure the directory exists, and do a lot of checking or find a library that does all that checking for you BUT (!) isn't the best way of checking to try ? If you check for permissions and the filesystem changes... you will have to change your code. But trying to write a file will ALWAYS tell you if you can write a file.
Your solution doesn't have to be the most elegant one. It's not a cheap hard coded patch or something ugly. It's just normal code. And it will always work. But if you don't like to see that check in the code just separate it by putting it in class which only goal is to check for the possibly of writing. In fact, you should put it in a utility class wheter you like the elegance or not.
The other solution would be to place your whole writing-to-the-hard-drive code, in the try. And if you can't write, the whole part will be skipped and you give feedback to the user with a message in the catch part.
it doesn't works even if you invoke canWrite on the final path?
File sample = new File(fileBrowse.getParent(),"empty.txt");
if (sample.canWrite()) {
doSomethingUseful(sample);
} else {
notifyUser();
}
you can use FilePermission to get the details .
I find one way where you need to implement SecurityManager the code is here and here
Using Java 1.8 I was able to use the following.
Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(Paths.get(destDir), LinkOption.NOFOLLOW_LINKS);
Assert.assertTrue("User did not have read permission.", permissions.contains(PosixFilePermission.OWNER_READ));
Assert.assertTrue("User did not have execute permission.", permissions.contains(PosixFilePermission.OWNER_EXECUTE));
Assert.assertTrue("User did not have write permission.", permissions.contains(PosixFilePermission.OWNER_WRITE));
Assert.assertFalse("Group did have read permission.", permissions.contains(PosixFilePermission.GROUP_READ));
Assert.assertFalse("Group did have execute permission.", permissions.contains(PosixFilePermission.GROUP_EXECUTE));
Assert.assertFalse("Group did have write permission.", permissions.contains(PosixFilePermission.GROUP_WRITE));
Assert.assertFalse("Others did have read permission.", permissions.contains(PosixFilePermission.OTHERS_READ));
Assert.assertFalse("Others did have execute permission.", permissions.contains(PosixFilePermission.OTHERS_EXECUTE));
Assert.assertFalse("Others did have write permission.", permissions.contains(PosixFilePermission.OTHERS_WRITE));