I'm creating a mini program that deletes Files using the File.delete() method but I'm having a little bit of an issue if I use the buffered Reader to read the .txt file before I delete it, it doesn't delete the file. I did come up with a solution for it: I just close the buffered reader before I delete the file. however this doesn't make sense to me as to why this is happening can anyone explain this.
import java.io.*;
import java.nio.file.Files;
public class Purge {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String sample;
boolean result = false;
BufferedReader amg = new BufferedReader(new FileReader("C:/Users/Steven/Desktop/me.txt"));
sample = amg.readLine();
amg.close();// closes the buffered reader
System.out.println("Haha I'm stille here: "+sample);
File anesu = new File("C:/Users/Steven/Desktop/me.txt");
if (anesu.exists()){
try{result = anesu.delete();
}catch( Exception x){
System.out.println("Problem Deleting File"+x);
}
catch( Throwable e){
System.out.println("Problem Deleting File Throwable"+e);
}
}else{
System.out.println("No File ");
}
System.out.println("File has been deleted: "+result);
}
}
When a stream object is garbage collected, its finalizer closes the underlying file descriptor. So, the fact that the delete only works when you added the System.gc() call is strong evidence that your code is somehow failing to close some stream for the file. It may well be a different stream object to the one that is opened in the code that you posted.
Note :
Properly written stream handling code uses a finally block to make sure that streams get closed no matter what.
If you does not want to use System.gc(), read your content with FileInputStream
InputStream in = new FileInputStream(new File("C:/temp/test.txt"));
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder out = new StringBuilder();
try {
String line;
while ((line = reader.readLine()) != null) {
out.append(line);
}
System.out.println(out.toString()); //Prints the string content read from input stream
}
catch(Exception ex) {//TODO}
finally {
reader.close();
}
You can delete the file in the finally block.
A downside to this approach is that if an exception is thrown the file will still be deleted.
public Stream<String> readLines(Path archive) {
try {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
(new FileInputStream(archive.toFile()))));
return bufferedReader.lines();
} catch (IOException e) {
throw new UncheckedIOException(e);
} finally {
try {
Files.delete(archive);
System.out.println("Deleted: " + archive);
} catch (IOException e) {
System.out.println("Unable to delete: " + archive);
}
}
}
Related
I wrote a method that prepares SQL insert statements and stores them in a text file. At this point it gets the job done, but I have a catch block that is a total eyesore. If I could somehow close a BufferedReader without implicitly calling flush that would be perfect. Is that possible? If yes, how?
As preparation for populating a master table with data on kanji(Japanese characters) for the memorization application I am making, I am making a list of all the characters. The data source is KANJIDIC2, a UTF-8 encoded xml file with data on 13k+ characters. The original idea was to include all the characters in the source file, but for some reason 300-or-so characters throw a java.nio.charset.MalformedInputException when I try to write them to my output file.
I decided to give up on those characters since they're not essential or anything, but I couldn't find a smooth way to close my BufferedReader after the exception above.
File outputFile = new File("C:\\Users\\tobbelobb\\Documents\\kanjilist.bsv");
try {
BufferedWriter bw = Files.newBufferedWriter(outputFile.toPath(), StandardCharsets.UTF_8);
for (Kanji nextKanji : kanjiList) {
try {
StringBuilder sb = new StringBuilder();
// sb.append stuff from list of objects...
bw.write(sb.toString());
bw.newLine();
bw.flush();
} catch (MalformedInputException ex) {
// Ungracefully swallow the exception.
ex.printStackTrace();
bw = Files.newBufferedWriter(outputFile.toPath(), StandardCharsets.UTF_8, StandardOpenOption.APPEND);
}
}
bw.close();
} catch (Exception ex) {
ex.printStackTrace();
}
I looked for a method to dispose of my BufferedReader object in the catch block, but the only one I could find is close(), which throws that same MalformedInputException again, and in the process writes an incomplete line of text to my file.
There is no such thing: https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/io/BufferedWriter.java#L258
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try {
flushBuffer();
} finally {
out.close();
out = null;
cb = null;
}
}
}
so it always tries to flush, and that is probably what most users expect anyway.
What you can do is to generate your lines separately, using an in-memory BufferedWriter. If it dies, you skip the line, if it works, you write it. Also, it is 2019 now, so please start using try-with-resources.
try(BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(outputFile))) {
for (Kanji nextKanji : kanjiList) {
try {
StringBuilder sb = new StringBuilder();
// sb.append stuff from list of objects...
ByteArrayOutputStream baos=new ByteArrayOutputStream();
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(baos));
bw.write(sb.toString());
bw.newLine();
bw.close();
baos.writeTo(bos);
} catch (MalformedInputException ex) {}
}
}
if it works at all (I am just writing from the top of my head), it can be prettier with a single ByteArrayOutputStream instance, and use its reset() in the loop.
Unable to delete files even after closing the corresponding readers and writers.
Permissions are present on the files
file.delete() returns false
my code
main(){
try{
File file=new File(path);// Path where the file is present
FileReader reader = new FileReader(path);
BufferedReader br = new BufferedReader(reader);
FileWriter writer = new FileWriter(pathOther);
BufferedWriter wr = new BufferedWriter(writer);
// Readers and writers for i/o operations
while((String str=br.readLine())!=null){
wr.write(str); // Copying to another file
}
}catch(Exception e){}
finally{
reader.close(); //close reader
writer.close(); //close writer
file.delete(); //This returns false
}
My guess as to what is going on is that you close the FileInputStream but leave the BufferedReader open, which leaves something holding on to the file handle. Then, when you try to delete the file, it returns false because something else has a handle on it.
Try the following code:
File file = new File(path);
try {
br = new BufferedReader(new FileReader(file));
// use the reader ...
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (br != null) br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
// now close the file
file.delete();
Update:
While testing the above code I noticed something else which could also cause the observations you were seeing. If the file at path does not exist, then logically calling file.delete will also fail for this reason. So you should make sure that the file actually exists before trying to delete it. You can call file.exists() to check for this.
First, you should close the BufferedReader instead of the FileReader (the BufferedReader will in turn call close() on the FileReader):
So instead of:
reader.close(); //close reader
do:
br.close();
(and leave out the complete redundant comment).
Also, since File.delete() simply returns a Boolean and doesn't tell you why it failed, you can get more information by calling Files.delete instead:
try {
Files.delete(file.toPath());
} catch (IOException e) {
// e now contains information about why it can't delete.
}
Nothing will work call System.gc();
I have few text files. Each text file contains some path and/or the reference of some other file.
File1
#file#>D:/FilePath/File2.txt
Mod1>/home/admin1/mod1
Mod2>/home/admin1/mod2
File2
Mod3>/home/admin1/mod3
Mod4>/home/admin1/mod4
All I want is, copy all the paths Mod1, Mod2, Mod3, Mod4 in another text file by supplying only File1.txt as input to my java program.
What I have done till now?
public void readTextFile(String fileName){
try {
br = new BufferedReader(new FileReader(new File(fileName)));
String line = br.readLine();
while(line!=null){
if(line.startsWith("#file#>")){
String string[] = line.split(">");
readTextFile(string[1]);
}
else if(line.contains(">")){
String string[] = line.split(">");
svnLinks.put(string[0], string[1]);
}
line=br.readLine();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Currently my code reads the contents of File2.txt only, control does not come back to File1.txt.
Please ask if more inputs are required.
First of all you are jumping to another file without closing the current reader and when you come back you lose the cursor. Read one file first and then write all its contents that match to another file. Close the current reader (Don't close the writer) and then open the next file to read and so on.
Seems pretty simple. You need to write your file once your svnLinks Map is populated, assuming your present code works (haven't seen anything too weird in it).
So, once the Map is populated, you could use something along the lines of:
File newFile = new File("myPath/myNewFile.txt");
// TODO check file can be written
// TODO check file exists or create
FileOutputStream fos = null;
OutputStreamWriter osw = null;
BufferedWriter bw = null;
try {
fos = new FileOutputStream(newFile);
osw = new OutputStreamWriter(fos);
bw = new BufferedWriter(osw);
for (String key: svnLinks.keySet()) {
bw.write(key.concat(" my separator ").concat(svnLinks.get(key)).concat("myNewLine"));
}
}
catch (Throwable t) {
// TODO handle more gracefully
t.printStackTrace();
if (bw != null) {
try {
bw.close();
}
catch (Throwable t) {
t.printStackTrace();
}
}
Here is an non-recursive implementation of your method :
public static void readTextFile(String fileName) throws IOException {
LinkedList<String> list = new LinkedList<String>();
list.add(fileName);
while (!list.isEmpty()) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(new File(list.pop())));
String line;
while ((line = br.readLine()) != null) {
if (line.startsWith("#file#>")) {
String string[] = line.split(">");
list.add(string[1]);
} else if (line.contains(">")) {
String string[] = line.split(">");
svnLinks.put(string[0], string[1]);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
br.close();
}
}
}
Just used a LinkedList to maintain the order. I suggest you to add some counter if you to limit the reading of files to a certain number(depth). eg:
while (!list.isEmpty() && readCount < 10 )
This will eliminate the chance of running the code to infinity(in case of circular reference).
Is there a way to check whether a file was correctly written, I mean if there is an EOF at the end?
I'm asking that because I have a program that takes some file, merge them in a very big file and then use it to get statistics from it.
The point is that the second part never ends because it doesn't recognize the end of file.
The relevant parts of the code are the following:
(please do not ask for the whole code as I cannot post for important reasons)
FileWriter file=null;
PrintWriter pw = null;
String pathToRead=null;
InputStreamReader isr = null;
BufferedReader br = null ;
FileInputStream fis = null ;
TestJFileChooser d=new TestJFileChooser();
int c=1;
String line=null;
....
//here i select the files
selectedFile=new File(pathToRead);
//here I get one buffer reader for each file got with listFiles()
for(File file_sel:app){
if (file_sel.getName().startsWith("gtou")){
System.out.println(file_sel.getName());
fis = null;
try {
fis = new FileInputStream(file_sel);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
isr=new InputStreamReader(fis);
br=new BufferedReader(isr);
map.put(i, br);
num_file++;
i++;
}
}
//then I select the output file and open a print writer for it
fileToWrite=new File(pathToRead);
try {
file = new FileWriter(fileToWrite);
pw= new PrintWriter(file);
} catch (IOException e1) {
e1.printStackTrace();
}
//merging part
....
line=br.readLine();
while(line!=null){
System.out.println("line is:"+line);
....
line=br.readLine();
}
//end of merging ....
pw.flush();
pw.close();
try {
if (file!=null) file.close();
fis.close();
isr.close();
br.close();
for(int fi=0;fi<num_file;fi++){
br2=map.get(fi);
br2.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
so.kill();
Runtime r=Runtime.getRuntime();
r.gc();
//this is a popup that comes out
GlitchSquad gli=new GlitchSquad("Completed");
the problem is that as output I get:
line is: null ;
line is: null ;
line is: null ;
etc
And never get to "completed" popup =(
I cannot understand what is exactly that null because the control line!=null doesn't work.
I also tried to use that null as a string ..but nothing..
I thought that was a problem in how I close the streams but now the code seems correct to me ..but still no way to stop it..
Suggestion?
Thanks in advance!
p.s. it is a summarized version in order to focus on the streams.. variables are correctly declared and the same is for imports etc
edit: code updated
EOF is EOF. There is no more data. Unless you have an expected EOF mark within the file, or a self-describing protocol that tells you where the EOF mark should be, there is no way to determine whether the file was completely written.
I don't know if it will solve your problem, but I'd be using this code instead:
try {
fis = new FileInputStream(file_sel);
isr=new InputStreamReader(fis);
br=new BufferedReader(isr);
map.put(num_file++, br);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Otherwise there may be uncaught "NullPointer"-exceptions or strange BufferedReaders in your "map". ( I don't right now know how new InputStreamReader(null) will behave.)
It looks like i and num_file have always equal values, so just drop i. Or use a LinkedList and drop both.
If there's not a special merging that you have to do, I'd just do it like this:
OutputStream os;
try {
os = new FileOuputStream(outfile);
} catch (FileNotFoundException e) {
os = null;
e.printStackTrace();
}
if (os != null) {
for(File file_sel:app) {
if (file_sel.getName().startsWith("gtou")) {
System.out.println(file_sel.getName());
InputStream is = null;
try {
is = new FileInputStream(file_sel);
byte[] buffer = new byte[1024];
int readBytes = 0;
while ((readBytes = is.read(buffer)) > 0) {
os.write(buffer, 0, readBytes);
}
fos.flush();
is.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
If you read files with different encodings, you will have to modify at least the reading of course.
If it doesn't work, I'd suggest you build a "summarized" and runable sample program.
The core of your question is this code:
BufferedReader br = ...
String line = br.readLine();
while (line != null) {
System.out.println("line is:" + line);
...
line = br.readLine();
}
You say that this repeatedly outputs this:
line is: null ;
line is: null ;
(Notice the " ;" on the end!!!)
The only way that can happen is if the file you are reading contains at least one line that look like this:
null ;
Indeed, unless the "..." code includes a continue statement, there must must be lots of those lines in the input file.
Is there a way to check whether a file was correctly written?
Yea. Look at it using a text editor and/or check its file size.
I mean if there is an EOF at the end?
In modern file systems, EOF is a position not a marker. Specifically it is the position after the last byte of the file. So it is logically impossible for a file to not have an EOF. (You'd have to have a file that is infinite in length for there to be no EOF.)
I have this method that gets the last line of a .txt file and creates a new temp file without that line. But when I try to delete the .txt that has the line I want to delete (so then I can rename the temp file) for some reason I can't. This is the code:
void removeFromLocal() throws IOException {
String lineToRemove = getLastLine();
File inputFile = new File("nexLog.txt");
File tempFile = new File("TempnexLog.txt");
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new FileReader(inputFile));
writer = new BufferedWriter(new FileWriter(tempFile));
String currentLine;
int i = 0;
while ((currentLine = reader.readLine()) != null) {
i++;
String trimmedLine = currentLine.trim();
if (!trimmedLine.equals(lineToRemove)) {
if (i != 1) {
writer.newLine();
}
writer.write(currentLine);
}
}
reader.close();
reader = null;
writer.flush();
writer.close();
writer = null;
System.gc();
inputFile.setWritable(true);
if (!inputFile.delete()) {
System.out.println("Could not delete file");
return;
}
if (!tempFile.renameTo(inputFile)) {
System.out.println("Could not rename file");
}
//boolean successful = tempFile.renameTo(inputFile);
} catch (IOException ex) {
Logger.getLogger(dropLog.class.getName()).log(Level.SEVERE, null, ex);
}
}
Whats funny is that when I press the button that calls the method once, nothing happens ("Could not delete file"), the second time it works fine and the 3rd I get "Could not rename file".
The file cannot be deleted when it's been opened by another process. E.g. in notepad or so or maybe even another FileReader/FileWriter on the file somewhere else in your code. Also, when you're executing this inside an IDE, you'll risk that the IDE will touch the file during the background scan for modifications in the project's folder. Rather store the files in an absolute path outside the IDE's project.
Also, the code flow of opening and closing the files has to be modified so that the close is performed in the finally block. The idiom is like this:
Reader reader = null;
try {
reader = new SomeReader(file);
// ...
} finally {
if (reader != null) try { reader.close(); } catch (IOException logOrIgnore) {}
}
Or, if you're already on Java 7, use the automatic resource management instead.
try (Reader reader = new SomeReader(file)) {
// ...
}
Further I recommend to use File#createTempFile() instead to create temp files. This way an unique temp filename will be generated and thus you prevent the very same temp file being written and renamed by multiple processes.
File tempFile = File.createTempFile("nexLog", ".txt");
Does BufferedReader close the nested reader (not mentioned in the doc)? You have to make sure, by checking if setWritable was successful.Otherwise you need to close FileReader too, and I would recommend because in case you close it twice there is no harm... by the way GC call is more harmful than useful.