I am trying to check if a folder is readable in Java 1.6 with the following two manner:
1) Using canRead method of File class. But it's readable all the time (canRead() return always true):
final File folder = new File("file.xml");
if(folder.canRead()){
// The file is readable
}else{
// The file is not readable!!
}
2) Using FilePermission class and catch exception. But it catchs the exception all the time (when the folder is readable or not):
try {
FilePermission filePermission = new FilePermission(folder.getAbsolutePath(), "read");
AccessController.checkPermission(filePermission);
// The file is readable
} catch (AccessControlException pACE) {
// The file is not readable !!
}
I have found that there is an issue between Microsoft Windows OS and Java 1.6 for this case.
Bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6203387
Have you any solution?
This is quick and dirty,
File dir = new File("foo");
if (dir.exists()) {
if (dir.listFiles() == null) {
// directory not readable
}
}
all the IO errors are handled inside of listFiles().
What I would do is simply go ahead with a write to that folder. If it works, then all is great, and if not, you can catch the exception.
This is philosophically a Pythonic approach
"It's better to ask for forgiveness than to ask for permission"
but you don't seem to have a choice here.
Here's a good StackOverflow post on exactly this Philosophy: https://stackoverflow.com/questions/6092992/why-is-it-easier-to-ask-forgiveness-than-permission-in-python-but-not-in-java (See 'Update #3' in the question which is a really good example, and somewhat relates to your problem)
Related
tl;dr I'm more used to writing command-line scripts that can just output based on the current working directory, so I'm unsure what directory to use for output files in a program that will be launched from a JAR.
Program Description:
My program builds an HTML file from data given to it from the rest of the program, and then is supposed to write it to a file that we'll call "Output.html" for simplicity.
Relevant Code:
public void outputHTML()
{
String output = buildHTML();
// Expanded to explain my confusion better
String fileDirectory = ""; // ???
String fileName = "Output.html";
String fullPath = fileDirectory + "\\" + fileName;
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fullPath)))
{
writer.write(output);
writer.close();
} catch (IOException e)
{
System.out.println("File not found.");
e.printStackTrace();
}
}
Problem
I don't know what to put the file directory as. Usually I run my programs from the command line and use ".\\Output.txt" as my output path, but I don't know where to put it if it's being run from a JAR.
The desired file structure is as follows:
Encompassing Folder
Program.jar
output
Output.html
Or alternatively (not sure if this makes it easier to understand or harder):
main\
main\Program.jar
main\output\
main\output\Output.html
Everything I can find on SE only relates to reading files that are both immutable and internal, but I'm trying to output a non-static file to a location outside of my jar.
Can anyone help with this? Thanks!
Misc Details
I'm using Eclipse without Gradle currently, because I don't know what Gradle is and new things are scary. If this particular problem would be easier to solve with Gradle, let me know and I'll look up more about it.
EDIT:
Added syntax highlighting to code block.
Formatted everything a bit better
Changed title to be more descriptive
You can use an absolute path: e.g. fileDirectory = "\\project\\test\\main\\output";
using normal slash should also work even on Windows ("/project/test/main/output")
Or use a relative path - this will start from the current working directory (user directory), the one where the JVM was started in - e.g. fileDirectory = "main\\output";
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 am getting a really strange behavior on a test server using Files.createFile().
With code looking like that :
Files.createFile(myPath);
... code adding that file to a zip file ...
The file created at myPath is SOMETIMES not included in the zip content, most often it is not included, no Exception thrown. I could never reproduce the issue outside of the test server which runs CentOS release 6.6 (Final) and has an ext4 file system. Performing a Files.exists(myPath) after createFile always returns true.
I tried writing a few characters to the file to check if it makes a difference, but it does not.
FileUtils.writeStringToFile(testLog.toFile(), "Test content");
If I add a short sleep in-between, the file is then included in the zip consistently.
Consistently working :
Files.createFile(myPath);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
//interrupted
}
... code adding that file to a zip file ...
My view on this is that there is some strange asynchronous behavior going on in the file system as a Thread.sleep() should never make any difference in this code.
Does anyone have a definite explanation on how that sleep can make a difference ?
EDIT : My problem here is really not about the zipping method but about the createFile method behaving asynchronously while it should not.
Thanks for your help !
Why don't you just use the zip filesystem provider?
final Path zipPath = Paths.get("pathToZipFileHere");
final URI uri = URI.create("jar:" + zipPath.toUri());
final Path fileInZip;
// Open the zip as a filesystem
try (
final FileSystem fs = FileSystems.newFileSystem(uri,
Collections.emptyMap());
) {
fileInZip = fs.getPath("path/in/zip");
// work with fileInZip
}
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.