I have been trying to delete a file in windows operating system using the Java IO file.delete() API. However it fails and returns false. The same code works like a charm in Ubuntu.
I have verified that the permissions of the file allows the program to delete it. Also all the input and output stream for the file has been opened as try with resources.
try (InputStream in = new FileInputStream(localFile); OutputStream out = new FileOutputStream(destinationFileName))
Using a debugger I have tested and found out that at the code line that I delete the file it returns true for following API calls.
file.exists()
file.canRead();
file.canWrite();
file.canExecute();
I have even tried adding System.gc() right before calling delete to make sure all the streams are closed.
Not sure whether this is helpful information but I have even tried using the Apache commons FileUtils.forceDelete(file) method and it has also been failed.
So what am I missing here?
Update:
By using Files.delete(Paths.get(file.getAbsolutePath())) I got the following error.
java.nio.file.FileSystemException: C:\Users\thuvvareka\Desktop\temp\in\sd.xml: The process cannot access the file because it is being used by another process.
at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
at java.nio.file.Files.delete(Files.java:1126)
at org.adroitlogic.x.transport.file.FileMessageInjector.finalizeProcessing(FileMessageInjector.java:161)
at org.adroitlogic.x.transport.file.FileMessageInjector.afterProcess(FileMessageInjector.java:123)
at org.adroitlogic.x.transport.file.FileMessageInjector.afterProcess(FileMessageInjector.java:37)
at org.adroitlogic.x.base.trp.ScheduledMessageInjector.lambda$2(ScheduledMessageInjector.java:72)
at org.adroitlogic.x.api.trp.MessageReceiver.lambda$receive$3(MessageReceiver.java:100)
at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
at org.adroitlogic.x.core.MessageContext.lambda$createNewResponseFuture$2(MessageContext.java:459)
at java.util.concurrent.CompletableFuture.uniWhenComplete(CompletableFuture.java:760)
at java.util.concurrent.CompletableFuture$UniWhenComplete.tryFire(CompletableFuture.java:736)
at java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:474)
at java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:1962)
at org.adroitlogic.x.core.MessageContext.completeMessageFlowSuccessfully(MessageContext.java:332)
at org.adroitlogic.x.base.connector.EgressConnectorElement.sendMessage(EgressConnectorElement.java:185)
at org.adroitlogic.x.base.connector.EgressConnectorElement.process(EgressConnectorElement.java:146)
at org.adroitlogic.x.base.processor.AbstractProcessingElement.processMessage(AbstractProcessingElement.java:103)
at org.adroitlogic.x.base.processor.TraceableProcessingElement.processMessage(TraceableProcessingElement.java:53)
at org.adroitlogic.x.base.connector.IngressConnectorElement.receiveMessage(IngressConnectorElement.java:119)
at org.adroitlogic.x.core.IntegrationPlatform.lambda$receive$0(IntegrationPlatform.java:81)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Welcome to Windows.
java.nio.file.FileSystemException: C:\Users\thuvvareka\Desktop\temp\in\sd.xml:
The process cannot access the file because it is being used by another process.
Typically, when a process has a file open in Windows, the operating system locks the file in a way that the file cannot be deleted. If it's your program that has the file open while you are trying to delete it, then close the file first and then delete it. If it's another program that has the file open, then you'll need to figure out who has it open and go from there.
When a process has a file open in Linux, there is typically nothing preventing you from deleting it, which is why you see different behavior.
I ran into this recently. I created a workaround where if file.delete() returns false I check if file.exists() returns true and if so, I wait a bit then try again and give up after some number of tries.
My unproven suspicion is that virus checkers on Windows lock the file to examine the file and waiting allows the virus checker to finish.
// Remove the original file.
if(!file.delete()) {
// wait a bit then retry on Windows
if (file.exists())
{
for (int i = 0; i < 6; i++)
{
Thread.sleep(500);
System.gc();
if (file.delete())
break;
}
Use Files.delete(filePath) instead of file.delete() as file.delete() has some issue regarding permission on windows.
I had the same issue.
Do out.close(); solve it.
System.gc() will not remove link to the OutputStream as long as you don't have close it.
Maybe you can use System.Runtime.exec() to run a terminal / command line command to delete a specific file. This may be somehow platform dependent, but the command to be entered to the exec() function may differ among os properties.
You can check this thread to determine the current os of the java program running.
How do I programmatically determine operating system in Java?
In linux, your line would be as follows:
System.Runtime.exec("rm <path to file>");
Related
i'm running java 1.7.0_21 on a windows 7 machine, and i try to delete a file on a ftp ubuntu-server. The following code snippet, shows what i do. the strange thing is, the file has the read, write and execute permission. the containing folder too. when i ask the bPermisison i receive true, but i can not delete this file....
The replyString gives the error 550 permission denied.
The same code snipped (and implementation) works fine on another ftp server.
I searched really long, but i didn't find any hint. does somebody know what's going wrong?
Thanks for any help.
String sFilePath = FileUtil.concatPath(sParamRemotedir, oFTPFile.getName(), "/");
boolean bPermission = FTPFile.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION);
boolean bDeleted = oFTPClient.deleteFile(sFilePath);
sReplyString = oFTPClient.getReplyString();
if(bRetrieveOK && !bDeleted) {
m_oDialogError.show(ErrorText.ERROR_TRASYSTHREAD_FTPMOVE_DELETEERROR, oFTPFile.getName(), oFTPClient.getReplyString());
bOK = false;
}
I too had the similar problem. Once I did the following everything is fine now.
With FTP it is not sufficient be owner of files and directories. The service and daemon FTP must be correctly configured in order to write and create files etc.
In Ubuntu:
Edit /etc/vsftpd.conf
sudo gedit /etc/vsftpd.conf
And in the line
#write_enable=YES
Remove # in front i.e.,
write_enable=YES
Finally restart the service:(this is very important)
sudo service vsftpd restart
I'm getting a different result for Files.exists(path) to path.toFile().exists() for a local file on Windows. I can see this file in Windows Explorer although I have (randomly) modified permissions and perhaps the permissions do not make sense.
However this doesn't explain why the old method returns true and the new methods returns false. The file definently exists but maybe it is invisible to the user running the Java code, so I'm not sure what the correct answer should be. Nor can I see how to see which user is running the code, there is only one real user Paul on the computer, but I'm wondering if whether if run as administrator or not effects things.
System.out.println("Path Exists(1):"+Files.exists(path));
System.out.println("Path Exist(2) :"+path.toFile().exists());
gives
Path Exists(1):false
Path Exist(2) :true
Also
System.out.println("Path readable(3) :"+Files.isReadable(path));
System.out.println("Path readable(4):"+path.toFile().canRead());
works in same way giving
Path readable(3) :false
Path readable(4):true
Permissions output
File C:\Code\jthink\opensrc\jaudiotagger\testdata\test157.dsf permissions
owner:PCLAPTOP\Paul
NT AUTHORITY\SYSTEM:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:DENY
BUILTIN\Administrators:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:DENY
BUILTIN\Administrators:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
NT AUTHORITY\SYSTEM:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/DELETE_CHILD/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/WRITE_ACL/WRITE_OWNER/SYNCHRONIZE:ALLOW
BUILTIN\Users:READ_DATA/READ_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/READ_ACL/SYNCHRONIZE:ALLOW
NT AUTHORITY\Authenticated Users:READ_DATA/WRITE_DATA/APPEND_DATA/READ_NAMED_ATTRS/WRITE_NAMED_ATTRS/EXECUTE/READ_ATTRIBUTES/WRITE_ATTRIBUTES/DELETE/READ_ACL/SYNCHRONIZE:ALLOW
c:\Code\jthink\opensrc\jaudiotagger>attrib C:\Code\jthink\opensrc\jaudiotagger\testdata\test157.dsf
A R C:\Code\jthink\opensrc\jaudiotagger\testdata\test157.dsf
Update
I dont have a conclusion but thought this information could be useful.
I was running code in IntelliJ IDE without the IDE Run program as Administrator option enabled, enabling this did then cause the Java application to also get the administrator privileges.
Interesting for another file I didn't add any DENY privileges, I just disabled inherit permissions and remove READ permissions from all groups. Then when I ran as user without run as admin enabled it could not read the file and also this code could not any output any information
AclFileAttributeView view = Files.getFileAttributeView(path, AclFileAttributeView.class);
if (view != null)
{
sb.append("Owner:"+view.getOwner().getName()+"**");
for (AclEntry acl : view.getAcl())
{
sb.append(acl.principal()+"**");
for(AclEntryPermission aep:acl.permissions())
{
sb.append(aep.toString() + "**");
}
}
}
but when I run with Run program as adminstrator enabled it still couldnt read the file, but the above code did now output some of the permissions as follows:
Owner:BUILTIN\Administrators
NT AUTHORITY\SYSTEM:WRITE_DATA/APPEND_DATA/WRITE_NAMED_ATTRS/WRITE_ATTRIBUTES/SYNCHRONIZE:ALLOW
PCLAPTOP\Paul:WRITE_DATA/APPEND_DATA/WRITE_NAMED_ATTRS/WRITE_ATTRIBUTES/SYNCHRONIZE:ALLOW
BUILTIN\Administrators:WRITE_DATA/APPEND_DATA/WRITE_NAMED_ATTRS/WRITE_ATTRIBUTES/SYNCHRONIZE:ALLOW
as you can see even though Administrators do not have READ or READ PERMISSIONS options they can output the permissions whereas before they couldn't, perhaps due to BUILTIN/Administraor being returned as owner.
Try reading this:
https://docs.oracle.com/javase/tutorial/essential/io/check.html
It states that, Files.exists(path) returning false does not mean that it does not exist, so yeah it would seem there is a permission problem. Try the Files.notExists(path) as well and see what it returns. If it is false it means that it can not be determined whether the file exists, but if it returns true, there is probably some problem in your code.
Try running your file from the command line instead of netbeans. If you don't know how to do this you can just search google, there is tons of stuff on this, but basically what you want to do is to compile the .java file with javac myfile.java and then run it with java myfile. Do this with a normal command prompt and one you open as administrator and see what you get.
Theses are two different methods: Files.exists() and path.toFile().exists().
Files.exists() defines that file denoted by this abstract pathname exists. In other words that file exists and user has READ access to it.
path.toFile().exists() indicates the file exists then there is no guarantee that a subsequence access will succeed. In other words file exist without checking that user has READ access to it.
It really depends on user which runs the program. When you work under your ID (Paul) it works fine. Especially in command line where you gan you ATTRIB command.
However, when you use some other application to run your code it depends on the system configuration. Run this ATTRIB or similar command inside your application and you will see.
I think you run some web site under IIS. This way is usually configured for lowest level user in the system with almost no rights to prevent security breaks. Usually it is everyone or NT AUTHORITY. As I can see this particular access has no rights to read your file
NT AUTHORITY\SYSTEM:READ_DATA/...:DENY
Naturally you have 2 different answers - FALSE: user which ID is used by running application cannot read this file, TRUE: file physically exist.
Change running ID for your application or grant READ access to everyone for this particular file including all directories in its path and you will have the same result in this two methods which check different meanings.
When a tool developed in Java is launched, it creates temporary files in a folder. If terminated properly those files are getting deleted , but if terminated with kill or pkill commands those files are not getting deleted. Is there any way to send a signal to java process to delete those files before terminating the process?
Please help me to solve this issue.
Thanks in Advance
It seems like File.deleteOnExit() is fragile when it comes to process termination. In contrast, using the NIO API with the StandardOpenOption.DELETE_ON_CLOSE seems to be more reliable even though it’s specification only says: “If the close method is not invoked then a best effort attempt is made to delete the file when the Java virtual machine terminates”
E.g. when running the following program:
File f1=File.createTempFile("deleteOnExit", ".tmp");
f1.deleteOnExit();
final Path f2 = Files.createTempFile("deleteOnClose", ".tmp");
FileChannel ch = FileChannel.open(f2, StandardOpenOption.DELETE_ON_CLOSE);
System.out.println(f1);
System.out.println(f2);
LockSupport.parkNanos(Long.MAX_VALUE);
// the following statement is never reached, but it’s here to avoid
// early cleanup of the channel by garbage collector
ch.close();
and killing the process while it hangs at parkNanos, the JVM leaves the deleteOnExit tmp file while correctly deleting the deleteOnClose file on my machine.
You can add shutdown hook and clean everything you need explicitly.
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
//put your shutdown code here
}
});
This is actually the same what java.io.File#deleteOnExit does for you.
I'm trying to use RemoveDrive.exe, found here, in my Java application. I have it in my JAR, and I'm extracting it to a temporary file using the following code, however when I try to run it I get an IOException which says CreateProcess error=5, Access is denied. The program doesn't normally need admin priviledges though. Any ideas on what could be causing the issue?
File RDexe = File.createTempFile("rmvd", ".exe");
InputStream exesrc = (InputStream) GraphicUI.class.getResource("RemoveDrive.exe").openStream();
FileOutputStream out = new FileOutputStream(RDexe);
byte[] temp = new byte[1024];
int rc;
while((rc = exesrc.read(temp)) > 0)
out.write(temp, 0, rc);
exesrc.close();
out.close();
RDexe.deleteOnExit();
// run executable
Runtime runtime = Runtime.getRuntime();
System.out.println(RDexe.getPath() + " " + "F:\\" + " -b -s");
Process proc = runtime.exec(RDexe.getPath() + " " + "F:\\" + " -b");
InputStream is = proc.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line; boolean ejected = false;
while((line = reader.readLine()) != null)
if(line.equalsIgnoreCase("failed")) ejected = false;
else if(line.equalsIgnoreCase("success")) ejected = true;
reader.close();
is.close();
UPDATE: If I enable the built-in Administrator account (net user administrator /active:yes), everything works fine from there. However if I right click and run as administrator in my standard account, I still get the error and UAC doesn't even ask for permission.
EDIT: Seeing as though the bounty is nearly finished, please see my SuperUser question which has helped me solve this problem... I'll be awarding the bounty and accepting an answer soon.
This may not be the problem in your situation, but some anti-virus programs will prevent executables or scripts inside temporary folders from being run. Instead of creating a temporary file, try putting it in the user directory:
File rdExe = new File(System.getProperty("user.home") + "/.yourProgramName/rmvd.exe");
rdExe.getParentFile().mkdirs();
just a heads up on another way to run files, have you thought of using the java Desktop object? : http://docs.oracle.com/javase/6/docs/api/java/awt/Desktop.html
i've found it useful when needing to run programs through my java program. something like this could work for you:
Desktop.getDesktop().open(new File("enter path and name of the file"));
hope you find it useful
I am not JAVA user but isn't it 32 vs. 64 bit issue ?
On 64 bit Windows error code 5 usually means that executable is not 64 bit compatible. Sometimes this is the case even when executable need to access only some (older win) system directory which does not exist anymore. To prove this try to use your executable in command line. if you can manage to get it work there than it is different issue. If not find executable for your OS.
Another possibility is that the file has to be physically present on some drive.
You wrote that you has it as temporary. Not shore what it means for JAVA. If it only copy it to some file and delete after use than its OK but if it is only in memory somewhere than that could be problem if executable need access to itself. To prove this just copy the file to some known location and then run it from there (in JAVA). if it works than you will need to do something about it (copy and delete executable from JAVA before and after execution to physical disk medium or whatever)
Another possibility is that error code 5 comes from JAVA environment an not from OS
In that case I have not a clue what it means (not JAVA user)
Seeing as though it has only been touched on here, I will say that the issue was related to permissions in Windows, and is not anything to do with Java.
As stated in the SuperUser question I've linked to in my original question, I found that my usual account did not have ownership of that folder for some unknown reason - so nothing could be executed; it wasn't just the temporary file I had created in Java.
Even though I am an administrator, in order to take ownership of the folder I had to enable the Built-In administrator account and grant myself ownership. Since I did that, it has all worked as expected.
Thanks to all for their efforts, I will award the bounty to the answer that was most detailed and put me on the right tracks.
What version of Windows are you running? Microsoft significantly tightened the restrictions around executing programs in Windows 7. My guess is that it the OS won't allow you to fork something that wasn't authenticated at the time your program was launched. I'd try running it on Windows 2000 or XP and see if you have the same issues.
It's quite possible i've misunderstood the purpose of the File dir argument in Runtime.exec(String command, String[] envp, File dir):
"The working directory of the new subprocess is specified by dir. If dir is null, the subprocess inherits the current working directory of the current process."
If I run Runtime.exec("C:/mydir/myfile.bat"); the script is executed (albeit with the wrong working dir)
however if I run Runtime.exec("myfile.bat", null, new File("C:/mydir")); i get the following error:
java.io.IOException: Cannot run program "myfile.bat" (in directory "C:\mydir"): CreateProcess error=2, The system cannot find the file specified
at java.lang.ProcessBuilder.start(ProcessBuilder.java:460)
at java.lang.Runtime.exec(Runtime.java:593)
I would assume that the dir argument sets the working directory for the new process as well as the command being executed, however maybe it just does the former. if that is the case the exception message is quite misleading.
How about
Runtime.exec("C:\mydir\myfile.bat", null, new File("C:\mydir"));
From ProcessBuilder.java
// It's much easier for us to create a high-quality error
// message than the low-level C code which found the problem.
Thats why you get a non specific exception - otherwise the JDK would need to implement exception handling similar to Spring's DataAccessException hierarchy handling OS specific error codes.
Edit: you may want to look at commons-exec
I do not know if it has something to do with it, but the \ is used to escape characters.
I always use forward slashes in Java and they are properly converted.
Otherwise I would recommend to always use \ i.e. double slashes to avoid mishaps like "C:\newfile" which would be C:-newline-ewfile.