This is my method to write to a file, this method belongs to a class
public void write(FileOutputStream fo) throws IOException
{
PrintWriter out=new PrintWriter(fo);
for (int i = 0; i < size; i++) {
String formatted="%3d";
for (int j=0;j<size;j++)
{
out.append(String.format(formatted,arr[i][j]));
}
out.append(System.getProperty("line.separator"));
}
out.append(System.getProperty("line.separator"));
out.close();
}
I want to write my results into many different files, corresponding to input files read by appropriate created object, so I pass the to-be-written file as a parameter to this method
It doesn't append at all
After spending hours searching for solution of this problem, I only got results of appending using PrintWriter with a specified path of file, for example:
PrintWriter out=new PrintWriter(new FileWriter("output1.txt",true));
If I use
PrintWriter out=new PrintWriter(new FileWriter(fo,true));
I encounter error
It doesn't append when write method of my 2 instances of that object is called
public void writeSolution() throws IOException
{
fo=new FileOutputStream("output\\output1.txt",true);
start.write(fo);
goal.write(fo);
fo.close();
}
Please help me solve this problem
When you close a PrintWriter, the close() method also closes the underlying stream/writer.
In every call to your write method, you open your PrintWriter and then you close it at the end. This means the stream is closed. Next time you open a PrintWriter to it, it is a closed file. You can't write to a closed file.
A PrintWriter does not throw exceptions when you do something like this, so it silently does nothing. And you are not calling its checkError() method, so you don't know that there was an error there.
What you should do is declare the PrintWriter as a field (so that it maintains its state between calls to write(), open it before you start calling the write() method, and close it after you finish calling the write() method for the last time. And remember to check errors.
Related
I have the following code:
CSVmaker(LinkedList data) {
String [] myLines = makeStrings(data);
// for (int k = 0; k<myLines.length; k++)
// System.out.println(myLines[]);
this.file = new File("rawdata.csv");
try {
BufferedWriter buff = new BufferedWriter(new FileWriter(file));
for (int i = 0; i<myLines.length; i++){
buff.write(myLines[i]);
buff.newLine();
System.out.println("done");
}
} catch (IOException ex) {
System.out.println("except");
}
}
No, I checked for the contents of myLines, these are correct.
Also, I get the print which prints "done" just as often as I should.
The csv is created.
However, if I open it manually, it is empty.
What can be the reason for this?
You never flush the buffer, or close the BufferedWriter.
After the for loop, make the following calls:
buff.flush();
buff.close();
Even with other resources, closing them when done is a good idea.
You have to close() the stream after use.
Call buff.close() after write loop; BufferedWriter will flush data to file at close.
Though the question is answered . I would like to add how buffer works.
whenever you try to write to a file using buffer,whatever you write gets added to the buffer. When the buffer is full the contents are written to the file . This way we are reducing the number of hits to the hard-drive hence improving the efficency.
If we want to forcefully write to a file without the buffer getting full , we use flush() method.
Starting with Java 8, one would simply do it with a try with resources, which automatically closes the BufferedWriter. Also see the usage of the new class Files
try (BufferedWriter writer = Files.newBufferedWriter(somePath, yourCharset)){
writer.write(output);
}
A part of my application writes data to a .csv file in the following way:
public class ExampleWriter {
public static final int COUNT = 10_000;
public static final String FILE = "test.csv";
public static void main(String[] args) throws Exception {
try (OutputStream os = new FileOutputStream(FILE)){
os.write(239);
os.write(187);
os.write(191);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
for (int i = 0; i < COUNT; i++) {
writer.write(Integer.toString(i));
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(checkLineCount(COUNT, new File(FILE)));
}
public static String checkLineCount(int expectedLineCount, File file) throws Exception {
BufferedReader expectedReader = new BufferedReader(new FileReader(file));
try {
int lineCount = 0;
while (expectedReader.readLine() != null) {
lineCount++;
}
if (expectedLineCount == lineCount) {
return "correct";
} else {
return "incorrect";
}
}
finally {
expectedReader.close();
}
}
}
The file will be opened in excel and all kind of languages are present in the data. The os.write parts are for prefixing the file with a byte order mark as to enable all kinds of characters.
Somehow the amount of lines in the file do not match the count in the loop and I can not figure out how. Any help on what I am doing wrong here would be greatly appreciated.
You simply need to flush and close your output stream (forcing fsync) before opening the file for input and counting. Try adding:
writer.flush();
writer.close();
inside your try-block. after the for-loop in the main method.
(As a side note).
Note that using a BOM is optional, and (in many cases) reduces the portability of your files (because not all consuming app's are able to handle it well). It does not guarantee that the file has the advertised character encoding. So i would recommend to remove the BOM. When using Excel, just select the file and and choose UTF-8 as encoding.
You are not flushing the stream,Refer oracle docs for more info
which says that
Flushes this output stream and forces any buffered output bytes to be
written out. The general contract of flush is that calling it is an
indication that, if any bytes previously written have been buffered by
the implementation of the output stream, such bytes should immediately
be written to their intended destination. If the intended destination
of this stream is an abstraction provided by the underlying operating
system, for example a file, then flushing the stream guarantees only
that bytes previously written to the stream are passed to the
operating system for writing; it does not guarantee that they are
actually written to a physical device such as a disk drive.
The flush method of OutputStream does nothing.
You need to flush as well as close the stream. There are 2 ways
manually call close() and flush().
use try with resource
As I can see from your code that you have already implemented try with resource and also BufferedReader class also implements Closeable, Flushable so use code as per below
public static void main(String[] args) throws Exception {
try (OutputStream os = new FileOutputStream(FILE); BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8))){
os.write(239);
os.write(187);
os.write(191);
for (int i = 0; i < COUNT; i++) {
writer.write(Integer.toString(i));
writer.newLine();
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(checkLineCount(COUNT, new File(FILE)));
}
When COUNT is 1, the code in main() will write a file with two lines, a line with data plus an empty line afterwards. Then you call checkLineCount(COUNT, file) expecting that it will return 1 but it returns 2 because the file has actually two lines.
Therefore if you want the counter to match you must not write a new line after the last line.
(As another side note).
Notice that writing CSV-files the way you are doing is really bad practice. CSV is not so easy as it may look at first sight! So, unless you really know what you are doing (so being aware of all CSV quirks), use a library!
In android, I am writing a file on clicking a button and on clicking next time, it saves the file and closes the buffered writer. But, I also want to implement functionality to close the buffered writer in onDestroy function. Before that I need to know if Bufferedwriter is already closed. How will I check if Buffered Writer is already closed?
In addition to that, does bufferedWriter.close() function set bufferedWriter to null?
Calling close method on already closed Writer has no impact.
Still, if you want to know if the Writer is closed, you can call writer.flush(), if it throws IOException then it means the Writer is already closed.
For your second question, closing a stream doesn't nullify the reference. You have to explicitly set it to null.
you can check if bufferredWriter not equal to null
if(bufferredWriter!=null)
{
bufferredWriter.close();
}
If you are using java7 or more then you need not to worry about closing the BufferredWriter
JDK 7 onwards you can make you of try with resource
for example
try(BufferredWriter bufferedWriter=new BufferredWriter())
{
//your code
}
catch(Exception e)
{
}
BufferedWriter vf = new BufferedWriter(new FileWriter("file"));
if (vf != null)
{
vf.close();
vf.close(); //won't cause any problem
}
you can close BufferedWriter as many times as you want if it is not null. So no need to check specifically if BufferedWriter is open or not.
Even better if you surround close statement in try/catch in case IOException occurs.
From javadocs
Closes the stream, flushing it first. Once the stream has been closed, further write() or flush() invocations will cause an IOException to be thrown. Closing a previously closed stream has no effect.
And as explained by sidgate, closing a stream won't nullify the reference you have to assign it manually.
bufferedWriter.close() - Closes this writer. The contents of the buffer are flushed, the target writer is closed, and the buffer is released. Only the first invocation of close has any effect.
Refer this
Also, you can check like this
Define below 2 variables as instance variable
BufferedWriter bufferWriter;
boolean isOpen = false;
Then,
try {
if (!isOpen) {
bufferWriter = new BufferedWriter(new FileWriter(file, true));
bufferWriter.write(initialData);
isOpen = true;
}
bufferWriter.write(remainingData);
bufferWriter.flush();
Log.d(TAG, "written to file:" + file.getAbsolutePath());
} catch (IOException e) {
Log.v("IOException", e.toString());
}
I need to dialogue with an external c++ console program (read output and write input). I read from the application with a Thread (and it works), but when it needs input, it works only the first time, then the stream probably remains empty, and it doesn't receive the second input (and external program closes).
The application i'm using is a simple .exe wrote in c++ that:
print "Insert first input"
scan input1
print input1
print "Insert second input"
scan input2
print input2
Main class:
import java.io.*;
import java.util.Scanner;
public class ExampleCom {
public static Communication com = new Communication();
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
String s;
com.read();
while(true)
{
s = in.nextLine();
com.write(s);
}
}
Communication class:
public class Communication
{
Process p;
OutputStream writer;
public InputStream reader = null;
Read r; //Class that with a loop read all exe input
Communication()
{
try{
p = Runtime.getRuntime ().exec ("C:\\esempio.exe");
writer = p.getOutputStream();
reader = p.getInputStream();
}catch(Exception e){}
}
public void read()
{
r = new Read();
Thread threadRead = new Thread(r);
threadRead.start();
}
public void write(String s)
{
try{
writer.write(s.getBytes());
writer.flush();
writer.close();
}catch(Exception e){}
}
}
How can I send my string (like "writer.write('hello')") when the external application needs it?
The problem is that in your write() method, you have the line
writer.close();
which means that after calling it the first time, you are closing the input stream to your C++. As far as it is concerned, it sees the "end of file" marker after your first input.
What you should do is put the close() in a separate method, and call that method only when you are done working with that process.
Now, as your target program expects text input and will only interpret the input if it gets an end-of-line (as per your answer to the question in my comment), you should supply that end-of-line to it.
Instead of doing raw byte-writes, I think a better approach would be to use a PrintWriter for that output stream, and use as naturally as you use System.out.println(). It can also save you on the flush() part.
You are interpreting it incorrectly when you see that your program is not reading the input until you close(). It's not waiting - it sends it as soon as you call flush(). But the C++ waits for either an end-of-file or an end-of-line, and since you are not giving it an end-of-line, then only close(), that sends it end-of-file, causes it to accept the input. But then you can no longer send any further data.
So the solution is, first, to define your writer as a PrintWriter. Instead of
OutputStream writer;
Use
PrintWriter writer;
And instead of
writer = p.getOutputStream();
Use
writer = new PrintWriter(p.getOutputStream(), true);
The true there will give you auto-flush whenever you use the println() command.
Now, your write method should be:
public void write(String s)
{
writer.println(s);
}
Note that a PrintWriter doesn't produce exceptions, so if you care about errors, you have to check for them using checkError().
And of course, have the close() in a separate method, as I mentioned before.
Because the write() method might throw an IOException, it is advisable to call the close() method inside a finally block.Place the writer.close() method outside the try clause:
finally {
if(writer != null) {
writer.close();
}
I have the following code:
CSVmaker(LinkedList data) {
String [] myLines = makeStrings(data);
// for (int k = 0; k<myLines.length; k++)
// System.out.println(myLines[]);
this.file = new File("rawdata.csv");
try {
BufferedWriter buff = new BufferedWriter(new FileWriter(file));
for (int i = 0; i<myLines.length; i++){
buff.write(myLines[i]);
buff.newLine();
System.out.println("done");
}
} catch (IOException ex) {
System.out.println("except");
}
}
No, I checked for the contents of myLines, these are correct.
Also, I get the print which prints "done" just as often as I should.
The csv is created.
However, if I open it manually, it is empty.
What can be the reason for this?
You never flush the buffer, or close the BufferedWriter.
After the for loop, make the following calls:
buff.flush();
buff.close();
Even with other resources, closing them when done is a good idea.
You have to close() the stream after use.
Call buff.close() after write loop; BufferedWriter will flush data to file at close.
Though the question is answered . I would like to add how buffer works.
whenever you try to write to a file using buffer,whatever you write gets added to the buffer. When the buffer is full the contents are written to the file . This way we are reducing the number of hits to the hard-drive hence improving the efficency.
If we want to forcefully write to a file without the buffer getting full , we use flush() method.
Starting with Java 8, one would simply do it with a try with resources, which automatically closes the BufferedWriter. Also see the usage of the new class Files
try (BufferedWriter writer = Files.newBufferedWriter(somePath, yourCharset)){
writer.write(output);
}