I have a java application that processes the contents of a file, and then I need to move it to another location.
This is how I read the file:
String filePath = new String("foo.bar");
String fileContents = new String("");
char[] myBuffer = new char[chunkSize];
int bytesRead = 0;
BufferedReader in;
try {
FileReader fr = new FileReader(filePath);
in = new BufferedReader(fr);
try {
while ((bytesRead = in.read(myBuffer,0,chunkSize)) != -1)
{
//System.out.println("Read " + bytesRead + " bytes. They were: " + new String(myBuffer));
fileContents+= new String(myBuffer).substring(0, bytesRead);
}
// close the stream as I don't need it anymore. (If I don't close it, then java would hold the file open thus preventing the subsequent move of the file)
in.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
return null;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return null;
}
the file should be closed as I close both input stream and file reader.
Then after this I try to move the file to another directory using File.renameTo(newFileName); but this fails (under unix!, under windows it works fine)
Right after the move fails, I test whether I can create a file called newFileName and whether I can delete the original file. The new file gets to be created, while the original file fails to delete.
Interestingly enough I can delete the original file from command line while the application is running (right after the failure).
Any idea why is that or any alternative?
More details: I am working under unix and I'm bound to use java 1.6 for legacy reasons (thus I can not revert to Files.move() which is supported starting from java 1.7).
I found what was the problem in my java application.
Basically I extract a list of files from a directory using a custom FileFilter. This gives me an array File[] foundFiles.
What I do afterwards is reading each file in a while loop using the snippet of code in the question.
Right after the file is read for some reason I created a new File object using the i-th file from the array as parameter for the constructor
File file = new File(foundFiles[i].getName()); // File to be moved
and then I tried to rename this one.
Now for some reason this works under windows while it doesn't under unix (the file is somehow locked I think by the foundFiles[i] object).
In fact if I print the results of these lines
System.out.println("I can read foundFiles[i]: " +foundFiles[i].canRead());// DEBUG
System.out.println("I can write foundFiles[i]: " +foundFiles[i].canWrite());// DEBUG
System.out.println("I can read file : " +file.canRead());// DEBUG
System.out.println("I can write file : " +file.canWrite());// DEBUG
I get
I can read foundFiles[i]: True
I can write foundFiles[i]: True
I can read file: False
I can write file: False
It was simply enough to use renameTo() directly on the foundFiles[i] objects to make it work fine.
Hope this helps, but I don't know why the first version would work under windows and not under unix.
Let's analyze the above observation...
I can read foundFiles[i]: True
I can write foundFiles[i]: True
I can read file: False
I can write file: False
The result is normal, because the file object has been produced via new File(foundFiles[i].getName()) but the method getName provides only the name of the file, WITHOUT its filepath !
By creating the file via new File(foundFiles[i].getParent() + File.separator + foundFiles[i].getName()), the results would then be :
I can read foundFiles[i]: True
I can write foundFiles[i]: True
I can read file: True
I can write file: True
Related
I have a program that have a file in which I write the progress I've done, so if the program is closed I can just re-read what I already did.
So if the file doesn't exist (first time I launch the program), I create it, and after that I write in it.
This work while I work with Eclipse. But since I exported to an Executable JAR, I have an error if the file already exists ! That is, I can create the file and write in it the first time, but not if I close and re-launch the program.
Here's the code :
String donePath = "./done.txt";
try {
File doneFile = new File(donePath);
doneFile.createNewFile();
allreadyDone = new ArrayList<String>(Arrays.asList(new String(
Files.readAllBytes(Paths.get(donePath))).split("\n")));
doneFileWriter = new FileWriter(donePath, true);
} catch (IOException e1) {
e1.printStackTrace();
}
and I'm getting :
java.io.FileNotFoundException: .\done.txt (Accès refusé)
at java.base/java.io.FileOutputStream.open0(Native Method)
at java.base/java.io.FileOutputStream.open(FileOutputStream.java:292)
at java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:235)
at java.base/java.io.FileOutputStream.<init>(FileOutputStream.java:156)
at java.base/java.io.FileWriter.<init>(FileWriter.java:82)
at =============.Main.main(Main.java:51)
I run your program (on Windows 10) with the extension of
printing the work already done
writing something (current time)
a finally-block that flushes and closes the doneFileWriter.
With the finally block everything is OK.
Without the finally block nothing is actually written.
I would expect "Accès refusé" if the log file is already open (by a different running instance).
Or if you run your code first with one user that owns the log file. And then use a different user for the next run, that has not write access.
You use the rather modern java.nio.Paths. So I suggest some type changes and debugging output:
Path donePath = Paths.get("./done.txt");
try {
File doneFile = donePath.toFile();
UserPrincipal owner = Files.getOwner(donePath);
String permissions = PosixFilePermissions.toString(
Files.getPosixFilePermissions(donePath));
System.out.println(
String.format("abs path:%s, owner:%s, can write:%b, permissions:%s",
doneFile.getAbsolutePath(), owner.getName(),
doneFile.canWrite(), permissions));
allreadyDone = new ArrayList<String>(Arrays.asList(new String(
Files.readAllBytes(donePath)).split("\n")));
What operating system do you use?
Which Java implementation (vendor/version)?
And what is your debug output?
You need to put the createNewFile() among an if-statement, so that if it is successfully created it goes ahead, and if it does not it simply outputs "File already exists".
try {
File myObj = new File(filename);
if (myObj.createNewFile()) {
System.out.println("File created: " + myObj.getName());
} else {
System.out.println("File already exists.");
}
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
This is currently what I have to delete the file but it's not working. I thought it may be permission problems or something but it wasn't. The file that I am testing with is empty and exists, so not sure why it doesn't delete it.
UserInput.prompt("Enter name of file to delete");
String name = UserInput.readString();
File file = new File("\\Files\\" + name + ".txt");
file.delete();
Any help would be GREATLY appreciated!
I now have:
File file = new File(catName + ".txt");
String path = file.getCanonicalPath();
File filePath = new File(path);
filePath.delete();
To try and find the correct path at run time so that if the program is transferred to a different computer it will still find the file.
The problem could also be due to any output streams that you have forgotten to close. In my case I was working with the file before the file being deleted. However at one place in the file operations, I had forgotten to close an output stream that I used to write to the file that was attempted to delete later.
Be sure to find out your current working directory, and write your filepath relative to it.
This code:
File here = new File(".");
System.out.println(here.getAbsolutePath());
... will print out that directory.
Also, unrelated to your question, try to use File.separator to remain OS-independent. Backslashes work only on Windows.
I got the same problem! then realized that my directory was not empty. I found the solution in another thread: not able to delete the directory through Java
/**
* Force deletion of directory
* #param path
* #return
*/
static public boolean deleteDirectory(File path) {
if (path.exists()) {
File[] files = path.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
deleteDirectory(files[i]);
} else {
files[i].delete();
}
}
}
return (path.delete());
}
Try closing all the FileOutputStream/FileInputStream you've opened earlier in other methods ,then try deleting ,worked like a charm.
I suspect that the problem is that the path is incorrect. Try this:
UserInput.prompt("Enter name of file to delete");
String name = UserInput.readString();
File file = new File("\\Files\\" + name + ".txt");
if (file.exists()) {
file.delete();
} else {
System.err.println(
"I cannot find '" + file + "' ('" + file.getAbsolutePath() + "')");
}
If you want to delete file first close all the connections and streams.
after that delete the file.
In my case it was the close() that was not executing due to unhandled exception.
void method() throws Exception {
FileInputStream fis = new FileInputStream(fileName);
parse(fis);
fis.close();
}
Assume exception is being thrown on the parse(), which is not handled in this method and therefore the file is not closed, down the road, the file is being deleted, and that delete statement fails, and do not delete.
So, instead I had the code like this, then it worked...
try {
parse(fis);
}
catch (Exception ex) {
fis.close();
throw ex;
}
so basic Java, which sometimes we overlook.
As other answers indicate, on Windows you cannot delete a file that is open. However one other thing that can stop a file from being deleted on Windows is if it is is mmap'd to a MappedByteBuffer (or DirectByteBuffer) -- if so, the file cannot be deleted until the byte buffer is garbage collected. There is some relatively safe code for forcibly closing (cleaning) a DirectByteBuffer before it is garbage collected here: https://github.com/classgraph/classgraph/blob/master/src/main/java/nonapi/io/github/classgraph/utils/FileUtils.java#L606 After cleaning the ByteBuffer, you can delete the file. However, make sure you never use the ByteBuffer again after cleaning it, or the JVM will crash.
I want to check if a specific file already exist in the same folder.
If it doesn't exist then create a new file and type in certain thing.
for example. if filePath = test.txt and test.txt doesn't exist.
Create a new file name test.txt and put 12345 in the first line of the file.
Currently my method wont even run this if statement despite the condition is met. (test.txt does not exist)
PrintWriter output;
File file = new File(filePath);
if(!file.isFile()){
try {
output = new PrintWriter(new FileWriter(filePath));
} catch (IOException ex) {
throw new PersistenceException("Error!", ex);
}
output.print("12345");
output.flush();
output.close();
}
You can check whether a file exist or not by creating a File object and using exist method. File objects are different in java compared to C, when you create a File object you do not necessarily create a physical file.
File file = new File(pathString);
if (file.exists())
{
// File already exists
}
else
{
// You can create your new file
}
I think you could use this condition in your if:
Files.exists(Paths.get(file))
You can decide to use the specification NOFOLLOW_LINKS in order to avoid to follow symbolic link.
This will help you to check if the file exists or not.
I hope this could help you.
I have this piece of code in my project:
String readFile() {
String pathname = saveDirectory + fileName + ".txt";
String content = "";
File f = new File(pathname);
if (f.exists() && !f.isDirectory()) {
try {
content = new String(Files.readAllBytes(Paths.get(pathname)));
}
catch (IOException e) { }
}
return content;
}
There are no errors, the aplication runs just right, but the content variable never has any text in it and I'm sure that the txt file has text in it!
I've already tried different ways to read the text file (with BufferedReader, Scanner, FileInputStream and FileReader) but none of them worked.
Ps. I'm almost sure that the problem isn't in the pathname variable since I've tried to open the file via code (with Runtime) and it opened the right file normally.
Ok, I tried adding the e.printStackTrace(); but there is still no errors, and it's not missing a / between the directory and the fileName, i've already added in the \\ in the directory variable.
Could you be forgetting the / between the directory and the file name? Print the content of pathname and see.
Or better: debug your code and see what happens.
It looks like you're opening the file once (File f = new File(pathname);), then trying to read it without using the file object you created. You're probably getting an IOException because Files.readAllBytes(Paths.get(pathname)) can't open the file while f has it open.
This is currently what I have to delete the file but it's not working. I thought it may be permission problems or something but it wasn't. The file that I am testing with is empty and exists, so not sure why it doesn't delete it.
UserInput.prompt("Enter name of file to delete");
String name = UserInput.readString();
File file = new File("\\Files\\" + name + ".txt");
file.delete();
Any help would be GREATLY appreciated!
I now have:
File file = new File(catName + ".txt");
String path = file.getCanonicalPath();
File filePath = new File(path);
filePath.delete();
To try and find the correct path at run time so that if the program is transferred to a different computer it will still find the file.
The problem could also be due to any output streams that you have forgotten to close. In my case I was working with the file before the file being deleted. However at one place in the file operations, I had forgotten to close an output stream that I used to write to the file that was attempted to delete later.
Be sure to find out your current working directory, and write your filepath relative to it.
This code:
File here = new File(".");
System.out.println(here.getAbsolutePath());
... will print out that directory.
Also, unrelated to your question, try to use File.separator to remain OS-independent. Backslashes work only on Windows.
I got the same problem! then realized that my directory was not empty. I found the solution in another thread: not able to delete the directory through Java
/**
* Force deletion of directory
* #param path
* #return
*/
static public boolean deleteDirectory(File path) {
if (path.exists()) {
File[] files = path.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
deleteDirectory(files[i]);
} else {
files[i].delete();
}
}
}
return (path.delete());
}
Try closing all the FileOutputStream/FileInputStream you've opened earlier in other methods ,then try deleting ,worked like a charm.
I suspect that the problem is that the path is incorrect. Try this:
UserInput.prompt("Enter name of file to delete");
String name = UserInput.readString();
File file = new File("\\Files\\" + name + ".txt");
if (file.exists()) {
file.delete();
} else {
System.err.println(
"I cannot find '" + file + "' ('" + file.getAbsolutePath() + "')");
}
If you want to delete file first close all the connections and streams.
after that delete the file.
In my case it was the close() that was not executing due to unhandled exception.
void method() throws Exception {
FileInputStream fis = new FileInputStream(fileName);
parse(fis);
fis.close();
}
Assume exception is being thrown on the parse(), which is not handled in this method and therefore the file is not closed, down the road, the file is being deleted, and that delete statement fails, and do not delete.
So, instead I had the code like this, then it worked...
try {
parse(fis);
}
catch (Exception ex) {
fis.close();
throw ex;
}
so basic Java, which sometimes we overlook.
As other answers indicate, on Windows you cannot delete a file that is open. However one other thing that can stop a file from being deleted on Windows is if it is is mmap'd to a MappedByteBuffer (or DirectByteBuffer) -- if so, the file cannot be deleted until the byte buffer is garbage collected. There is some relatively safe code for forcibly closing (cleaning) a DirectByteBuffer before it is garbage collected here: https://github.com/classgraph/classgraph/blob/master/src/main/java/nonapi/io/github/classgraph/utils/FileUtils.java#L606 After cleaning the ByteBuffer, you can delete the file. However, make sure you never use the ByteBuffer again after cleaning it, or the JVM will crash.