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));
}
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 need to write a custom batch File renamer. I've got the bulk of it done except I can't figure out how to check if a file is already open. I'm just using the java.io.File package and there is a canWrite() method but that doesn't seem to test if the file is in use by another program. Any ideas on how I can make this work?
Using the Apache Commons IO library...
boolean isFileUnlocked = false;
try {
org.apache.commons.io.FileUtils.touch(yourFile);
isFileUnlocked = true;
} catch (IOException e) {
isFileUnlocked = false;
}
if(isFileUnlocked){
// Do stuff you need to do with a file that is NOT locked.
} else {
// Do stuff you need to do with a file that IS locked
}
(The Q&A is about how to deal with Windows "open file" locks ... not how implement this kind of locking portably.)
This whole issue is fraught with portability issues and race conditions:
You could try to use FileLock, but it is not necessarily supported for your OS and/or filesystem.
It appears that on Windows you may be unable to use FileLock if another application has opened the file in a particular way.
Even if you did manage to use FileLock or something else, you've still got the problem that something may come in and open the file between you testing the file and doing the rename.
A simpler though non-portable solution is to just try the rename (or whatever it is you are trying to do) and diagnose the return value and / or any Java exceptions that arise due to opened files.
Notes:
If you use the Files API instead of the File API you will get more information in the event of a failure.
On systems (e.g. Linux) where you are allowed to rename a locked or open file, you won't get any failure result or exceptions. The operation will just succeed. However, on such systems you generally don't need to worry if a file is already open, since the OS doesn't lock files on open.
// TO CHECK WHETHER A FILE IS OPENED
// OR NOT (not for .txt files)
// the file we want to check
String fileName = "C:\\Text.xlsx";
File file = new File(fileName);
// try to rename the file with the same name
File sameFileName = new File(fileName);
if(file.renameTo(sameFileName)){
// if the file is renamed
System.out.println("file is closed");
}else{
// if the file didnt accept the renaming operation
System.out.println("file is opened");
}
On Windows I found the answer https://stackoverflow.com/a/13706972/3014879 using
fileIsLocked = !file.renameTo(file)
most useful, as it avoids false positives when processing write protected (or readonly) files.
org.apache.commons.io.FileUtils.touch(yourFile) doesn't check if your file is open or not. Instead, it changes the timestamp of the file to the current time.
I used IOException and it works just fine:
try
{
String filePath = "C:\sheet.xlsx";
FileWriter fw = new FileWriter(filePath );
}
catch (IOException e)
{
System.out.println("File is open");
}
I don't think you'll ever get a definitive solution for this, the operating system isn't necessarily going to tell you if the file is open or not.
You might get some mileage out of java.nio.channels.FileLock, although the javadoc is loaded with caveats.
Hi I really hope this helps.
I tried all the options before and none really work on Windows. The only think that helped me accomplish this was trying to move the file. Event to the same place under an ATOMIC_MOVE. If the file is being written by another program or Java thread, this definitely will produce an Exception.
try{
Files.move(Paths.get(currentFile.getPath()),
Paths.get(currentFile.getPath()), StandardCopyOption.ATOMIC_MOVE);
// DO YOUR STUFF HERE SINCE IT IS NOT BEING WRITTEN BY ANOTHER PROGRAM
} catch (Exception e){
// DO NOT WRITE THEN SINCE THE FILE IS BEING WRITTEN BY ANOTHER PROGRAM
}
If file is in use FileOutputStream fileOutputStream = new FileOutputStream(file); returns java.io.FileNotFoundException with 'The process cannot access the file because it is being used by another process' in the exception message.
I'm trying to create a directory hierarchy and then copy a file from my assets into the newly created directory. I've used the code samples offered here on stackoverflow but I'm not getting anywhere. Essentially my code goes like this:
InputStream in = getAssets.open(mydb.sqlite);
File dir = new File("/data/data/my.package/databases/");
dir.mkdirs();
out = new FileOutputStream("/data/data/my.package/databases/mydb.sqlite");
while ((len = in.read(buffer)) > 0)
{
out.write(buffer, 0, len);
}
out.flush();
out.close();
in.close
This is all done within the main activity on first launch and of course should only be done once. Before the code runs, the only directory that exists is /data/. Yes, it is a database file but that shouldn't matter at this point since I'm just copying the file and haven't yet tried to access it with the database code.
The code doesn't throw any exceptions, and dir.mkdirs() returns true. Regardless, the directories are not created and the file is not copied. I have added the permissions line for WRITE_EXTERNAL_STORAGE to my manifest as has been suggested in several places, FWIW. I can step through the code and everything appears to be fine. But of course it's not.
What do I need to be looking for here? File permissions problems? Why does the code think everything is there (ie, when it gets to the copy code, it doesn't throw FileNotFoundException) but in reality there's nothing on the file system?
Edit: Here's what I've learned. getDir() creates the directory in /data/data/my.package/app_*. Not sure why it uses this prefix on the directory name. This won't work if you need to put something in a standard location such as databases/ or files/.
Use openFileOutput instead as /data/data is internal storage and you should only use the Android APIs to get a file handle there. See: http://developer.android.com/guide/topics/data/data-storage.html#filesInternal
Edit:
/data/data/my.package is handled by openFileOutput/getDir so you would create your directory with getDir('databases',MODE_PRIVATE) and create your file there.
Edit2:
From getDir documentation:
You can use the returned File object to create and access files in this directory.
A program we have erred when trying to move files from one directory to another. After much debugging I located the error by writing a small utility program that just moves a file from one directory to another (code below). It turns out that while moving files around on the local filesystem works fine, trying to move a file to another filesystem fails.
Why is this? The question might be platform specific - we are running Linux on ext3, if that matters.
And the second question; should I have been using something else than the renameTo() method of the File class? It seems as if this just works on local filesystems.
Tests (run as root):
touch /tmp/test/afile
java FileMover /tmp/test/afile /root/
The file move was successful
touch /tmp/test/afile
java FileMover /tmp/test/afile /some_other_disk/
The file move was erroneous
Code:
import java.io.File;
public class FileMover {
public static void main(String arguments[] ) throws Exception {
boolean success;
File file = new File(arguments[0]);
File destinationDir = new File(arguments[1]);
File destinationFile = new File(destinationDir,file.getName() );
success = file.renameTo(destinationFile);
System.out.println("The file move was " + (success?"successful":"erroneous"));
}
}
Java 7 and above
Use Files.move(Path source, Path target, CopyOption... opts).
Note that you must not provide the ATOMIC_MOVE option when moving files between file systems.
Java 6 and below
From the docs of File.renameTo:
[...] The rename operation might not be able to move a file from one filesystem to another [...]
The obvious workaround would be to copy the file "manually" by opening a new file, write the content to the file, and delete the old file.
You could also try the FileUtils.moveFile method from Apache Commons.
Javadoc to the rescue:
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.
From the docs:
Renames the file denoted by this abstract pathname.
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.
If you want to move file between different file system you can use Apache's moveFile
your ider is error
beause /some_other_disk/ is relative url but completely url ,can not find the url
i have example
java FileMover D:\Eclipse33_workspace_j2ee\test\src\a\a.txt D:\Eclipse33_workspace_j2ee\test\src
The file move was successful
java FileMover D:\Eclipse33_workspace_j2ee\test\src\a\a.txt \Eclipse33_workspace_j2ee\test\src
The file move was erronous
result is url is error
I am trying to copy a file using the following code:
File targetFile = new File(targetPath + File.separator + filename);
...
targetFile.createNewFile();
fileInputStream = new FileInputStream(fileToCopy);
fileOutputStream = new FileOutputStream(targetFile);
byte[] buffer = new byte[64*1024];
int i = 0;
while((i = fileInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, i);
}
For some users the targetFile.createNewFile results in this exception:
java.io.IOException: The filename, directory name, or volume label syntax is incorrect
at java.io.WinNTFileSystem.createFileExclusively(Native Method)
at java.io.File.createNewFile(File.java:850)
Filename and directory name seem to be correct. The directory targetPath is even checked for existence before the copy code is executed and the filename looks like this: AB_timestamp.xml
The user has write permissions to the targetPath and can copy the file without problems using the OS.
As I don't have access to a machine this happens on yet and can't reproduce the problem on my own machine I turn to you for hints on the reason for this exception.
This can occur when filename has timestamp with colons, eg. myfile_HH:mm:ss.csv Removing colons fixed the issue.
Try this, as it takes more care of adjusting directory separator characters in the path between targetPath and filename:
File targetFile = new File(targetPath, filename);
I just encountered the same problem. I think it has to something do with write access permission. I got the error while trying to write to c:\ but on changing to D:\ everything worked fine.
Apparently Java did not have permission to write to my System Drive (Running Windows 7 installed on C:)
Here is the test program I use
import java.io.File;
public class TestWrite {
public static void main(String[] args) {
if (args.length!=1) {
throw new IllegalArgumentException("Expected 1 argument: dir for tmp file");
}
try {
File.createTempFile("bla",".tmp",new File(args[0]));
} catch (Exception e) {
System.out.println("exception:"+e);
e.printStackTrace();
}
}
}
Try to create the file in a different directory - e.g. "C:\" after you made sure you have write access to that directory. If that works, the path name of the file is wrong.
Take a look at the comment in the Exception and try to vary all the elements in the path name of the file. Experiment. Draw conclusions.
Remove any special characters in the file/folder name in the complete path.
Do you check that the targetPath is a directory, or just that something exists with that name? (I know you say the user can copy it from the operating system, but maybe they're typing something else).
Does targetPath end with a File.separator already?
(It would help if you could log and tell us what the value of targetPath and filename are on a failing case)
Maybe the problem is that it is copying the file over the network, to a shared drive? I think java can have problems when writing files using NFS when the path is something like \mypc\myshared folder.
What is the path where this problem happens?
Try adding some logging to see exactly what is the name and path the file is trying to create, to ensure that the parent is well a directory.
In addition, you can also take a look at Channels instead of using a loop. ;-)
You say "for some users" - so it works for others? What is the difference here, are the users running different instances on different machines, or is this a server that services concurrent users?
If the latter, I'd say it is a concurrency bug somehow - two threads check try to create the file with WinNTFileSystem.createFileExclusively(Native Method) simultaniously.
Neither createNewFile or createFileExclusively are synchronized when I look at the OpenJDK source, so you may have to synchronize this block yourself.
Maybe the file already exists. It could be the case if your timestamp resolution is not good enough. As it is an IOException that you are getting, it might not be a permission issue (in which case you would get a SecurityException).
I would first check for file existence before trying to create the file and try to log what's happening.
Look at public boolean createNewFile() for more information on the method you are using.
As I was not able to reproduce the error on my own machine or get hands on the machine of the user where the code failed I waited until now to declare an accepted answer.
I changed the code to the following:
File parentFolder = new File(targetPath);
... do some checks on parentFolder here ...
File targetFile = new File(parentFolder, filename);
targetFile.createNewFile();
fileInputStream = new FileInputStream(fileToCopy);
fileOutputStream = new FileOutputStream(targetFile);
byte[] buffer = new byte[64*1024];
int i = 0;
while((i = fileInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, i);
}
After that it worked for the user reporting the problem.
So it seems Alexanders answer did the trick - although I actually use a slightly different constructor than he gave, but along the same lines.
I yet have to talk that user into helping me verifying that the code change fixed the error (instead of him doing something differently) by running the old version again and checking if it still fails.
btw. logging was in place and the logged path seemed ok - sorry for not mentioning that. I took that for granted and found it unnecessarily complicated the code in the question.
Thanks for the helpful answers.
A very similar error:-
" ... java.io.IOException: The filename, directory name, or volume label syntax is incorrect"
was generated in Eclipse for me when the TOMCAT home setting had a training backslash.
The minor edit suggested at:-
http://www.coderanch.com/t/556633/Tomcat/java-io-IOException-filename-directory
fixed it for me.
FileUtils.copyFile(src,new File("C:\\Users\\daiva\\eclipse-workspace\\PracticeProgram\\Screenshot\\adi.png"));
Try to copy file like this.