Write to the same file using BufferWriter from multiple classes - java

I want to output my result to a file. I use BufferWriter as below:
public class class1{
...
void print()
{
System.out.println("The name "+outName()+" Tel: "+outNumber());
try{
PrintWriter printWriter=new PrintWriter(new BufferedWriter(new FileWriter("myfile.txt", true)));
printWriter.println("The name "+outName()+" Tel: "+outNumber());
}catch (IOException e){}
}
}
However I have another class and main function also having their own print functions
public class class2{
...
void print()
{
System.out.println("The name "+outName()+" Tel: "+outNumber());
try{
PrintWriter printWriter=new PrintWriter(new BufferedWriter(new FileWriter("myfile.txt", true)));
printWriter.println("The name "+outName()+" Tel: "+outNumber());
}catch (IOException e){}
}
}
public static void main(String[] args) throws IOException{
try{
PrintWriter printWriter=new PrintWriter(new BufferedWriter(new FileWriter("myfile.txt", true)));
...
printWriter.println("something");
printWriter.close();
}catch(IOException e){ }
}
The code pass the compilation, but only the output from the main function appear in the output file. How to fix it please?

There are three (OK ... make that four, no five) significant problems with your code.
In class2 you don't close or flushthePrintWriter` after you have finished writing. That means that the data will never be written out to the file. That's why you never see the output.
This is the obvious bug. But the rest of the problems are also important. Arguably MUCH MORE important ... so keep reading.
The print() method in class2 leaks file descriptors (!). Each time you call it, it will open a file descriptor, write stuff ... and drop it on the floor. If you call print() repeatedly, the FileWriter constructor will fail. You need to close the file, and the cleanest way to ensure it always happens is to write the code like this:
try (PrintWriter printWriter =
new PrintWriter(new BufferedWriter(
new FileWriter("myfile.txt", true)))) {
printWriter.println(...);
}
This is a "try with resource" ... and it guarantees that the resource (printWriter) will be closed when the scope exits.
You are squashing exceptions.
try {
PrintWriter printWriter - ...
} catch (IOException e) {
// SQUASH!!!
}
This is really, really bad. Basically, you have written your code to ignore the exception. Pretend it never happened ... and throw away the information in the exception that would say why it happened.
You should only ever squash an exception if you are absolutely sure that you will only catch expected exceptions, and that ignoring them is absolutely correct. Here, it isn't. If an IOException is thrown here, you need to know why!
Opening multiple streams to write to the same file is a recipe for problems. The streams won't be synchronized, and you are likely to see the output interleaved in the output file in unexpected ways. If the output pipelines include buffering (like yours do), the problem is worse.
You have serious Java style issues:
A class name should always start with an uppercase letter. Always. Even in example code snippets ...
Code should be consistently indented. I recommend using SP characters rather than TAB characters because tabs don't display consistently.
There are style rules about where you should and should not put spaces and line breaks. For example, there should always be whitespace around a binary operator. Find a Java style guide, read it and format your code accordingly.
Always write your code so that >>other people<< can read it.

I think you need to call new class1().print() or new class2().print(), i.e. you need to instantiate the instances first.
Also please remember to close the file in each print() function.

It's because you're never closing anything exept in main(). You're also swallowing exceptions, so you're concealing the truth from yourself. Don't do that.
But it's poor practice. You should keep the file open and use the same FileWriter, BufferedWriter, PrintWriter, and synchronize access to them so you don't get interleaved data.
Not a good idea overall.

Related

Rollback or Reset a BufferedWriter

A logic that handles the rollback of a write to a file is this possible?
From my understanding a BufferWriter only writes when a .close() or .flush() is invoked.
I would like to know is it possible to, rollback a write or undo any changes to a file when an error has occurred?
This means that the BufferWriter acts as a temporary storage to store the changes done to a file.
How big is what you're writing? If it isn't too big, then you could write to a ByteArrayOutputStream so you're writing in memory and not affecting the final file you want to write to. Only once you've written everything to memory and have done whatever you want to do to verify that everything is OK can you write to the output file. You can pretty much be guaranteed that if the file gets written to at all, it will get written to in its entirety (unless you run out of disk space.). Here's an example:
import java.io.*;
class Solution {
public static void main(String[] args) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
try {
// Do whatever writing you want to do here. If this fails, you were only writing to memory and so
// haven't affected the disk in any way.
os.write("abcdefg\n".getBytes());
// Possibly check here to make sure everything went OK
// All is well, so write the output file. This should never fail unless you're out of disk space
// or you don't have permission to write to the specified location.
try (OutputStream os2 = new FileOutputStream("/tmp/blah")) {
os2.write(os.toByteArray());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
If you have to (or just want to) use Writers instead of OutputStreams, here's the equivalent example:
Writer writer = new StringWriter();
try {
// again, this represents the writing process that you worry might fail...
writer.write("abcdefg\n");
try (Writer os2 = new FileWriter("/tmp/blah2")) {
os2.write(writer.toString());
}
} catch (IOException e) {
e.printStackTrace();
}
It is impossible to rollback or undo changes already applied to files/streams,
but there are tons of alternatives to do so:
One simple trick is to clean the destination and redo the process again, to clean the file:
PrintWriter writer = new PrintWriter(FILE_PATH);
writer.print("");
// other operations
writer.close();
You can remove the content entirely and re-run again.
Or if you are sure the last line(s) are the problems, you may do remove last line actions for your purpose, such as rollback the line instead:
Delete last line in text file

Why I couldn't write all the characters to the file with java FileWriter? [duplicate]

I have a Java program that reads some text from a file, line by line, and writes new text to an output file. But not all the text I write to my BufferedWriter appears in the output file after the program has finished. Why is that?
The details: the program takes a CSV text document and converts it into SQL commands to insert the data into a table. The text file has more than 10000 lines which look similar to following:
2007,10,9,1,1,1006134,19423882
The program seems to work fine except it just stops in the file randomly half way through creating a new SQL statement having printed it into the SQL file. It looks something like:
insert into nyccrash values (2007, 1, 2, 1, 4, 1033092, 259916);
insert into nyccrash values (2007, 1, 1, 1, 1, 1020246, 197687);
insert into nyccrash values (2007, 10, 9, 1
This happens after about 10000 lines but several hundred lines before the end of the file. Where the break happens is between a 1 and a ,. However, the characters doesn't seem important because if I change the 1 to a 42 the last thing written to the new file is 4, which is cutting off the 2 from that integer. So it seems like the reader or writer must just be dying after writing/reading a certain amount.
My Java code is as follows:
import java.io.*;
public class InsertCrashData
{
public static void main (String args[])
{
try
{
//Open the input file.
FileReader istream = new FileReader("nyccrash.txt");
BufferedReader in = new BufferedReader(istream);
//Open the output file.
FileWriter ostream = new FileWriter("nyccrash.sql");
BufferedWriter out = new BufferedWriter(ostream);
String line, sqlstr;
sqlstr = "CREATE TABLE nyccrash (crash_year integer, accident_type integer, collision_type integer, weather_condition integer, light_condition integer, x_coordinate integer, y_coordinate integer);\n\n";
out.write(sqlstr);
while((line = in.readLine())!= null)
{
String[] esa = line.split(",");
sqlstr = "insert into nyccrash values ("+esa[0]+", "+esa[1]+", "+esa[2]+", "+esa[3]+", "+esa[4]+", "+esa[5]+", "+esa[6]+");\n";
out.write(sqlstr);
}
}
catch(Exception e)
{
System.out.println(e);
}
}
}
You need to close your OutputStream which will flush the remainder of your data:
out.close();
The default buffer size for BufferedWriter is 8192 characters, large enough to easily hold hundreds of lines of unwritten data.
You must close() your BufferedWriter. You must close() your BufferedWriter because it IS-A Writer and thus implements AutoCloseable, which means (emphasis added) it is
A resource that must be closed when it is no longer needed.
Some people say you must first call flush() for your BufferedWriter before calling close(). They are wrong. The documentation for BufferedWriter.close() notes that it "Closes the stream, flushing it first" (emphasis added).
The documented semantics of flushing (flush()) are
Flushes this stream by writing any buffered output to the underlying stream
So, you must close, and close will flush any buffered output.
Your output file does not include all the text you wrote to your BufferedWriter because it stored some of that text in a buffer. The BufferedWriter never emptied that buffer, passing it through to the file, because you never told it to do so.
Since Java 7, the best way to ensure an AutoCloseable resource, such as a BufferedWriter, is closed when it is not longer need is to use automatic resource management (ARM), also known as try-with-resources:
try (BufferedWriter out = new BufferedWriter(new FileWriter(file))) {
// writes to out here
} catch (IOException ex) {
// handle ex
}
You must also close your BufferedReader when it is no longer need, so you should have nested try-with-resources blocks:
try (BufferedReader in = new BufferedReader(new FileReader("nyccrash.txt")) {
try (BufferedWriter out = new BufferedWriter(new FileWriter("nyccrash.sql"))) {
// your reading and writing code here
}
} catch (IOException ex) {
// handle ex
}
Do not be tempted (as other answers here suggest) just to call close() at the end of your method, when your code has "finished" using the writer. That will not work if your writing code throws an exception, and in particular if it throws an IOException.
A resource that must be closed when it is no longer needed.
finally {
out.close();//this would resolve the issue
}
Some things to consider:
BufferedWriter.close() flushes the buffer to the underlying stream, so if you forget to flush() and don't close, your file may not have all the text you wrote to it.
BufferedWriter.close() also closes the wrapped Writer. When that's a FileWriter, this will ultimately close a FileOutputStream and tell the OS that you're done writing to the file.
The garbage collector will automatically call close(), not on the BufferedWriter or the wrapped FileWriter, but on the FileOuputStream. So the OS will be happy, but you have to wait for the GC.
However, you always want to release OS resources as soon as you no longer need them. This goes for open files, database connections, print queues ... anything. Trust me on this one.
BufferedWriter.close() does clear up the internal character buffer, so that memory will be available for garbage collection, even while the BufferedWriter itself remains in scope.
So, Always close your resources (not just files) when you're done with them.
If you really want a peek under the covers, most of the Java API's source is available. BufferedWriter is here.
Your code does not appear to be closing the writer after you've finished writing to it. Add an out.close() (preferably in a finally block) and it should work properly.
you dint close your BufferedWriter.close it inside a finally block
finally {
out.close();//this would resolve the issue
}
Always close your resources (not just files) when you're done with them.
finally {
out.close();//this would resolve the issue
}
There might be situations when you want to flush the buffer without closing the file. In these situations you can use the flush-method.
Since you're using BufferedWriter you can also flush the buffer when appropriate:
out.flush()
This will write the rest of the buffer to the actual file. Close-method also flushes the buffer and closes the file.
out.close()
There might be situations when you want to flush the buffer without closing the file. In these situations you can use the flush-method.
You can also use BuffredWriter's newline-method instead of adding \n to the end of the line. Newline-method uses system specific line separator so your code works on different platforms.
out.newLine()
According to documentation it is no use calling flush() method. If you intent to use FileWriter then flush() would help you out.
Basically in this case, you just need to close, BufferedWriter.close() only. This will flush the remainder of your data.
create finally block and put the close method inside so that it will put all data without missing.
finally {
out.close();
}

Write and close BufferedWriter in single line code snippet

I've below code snippet.
Map<String, Object> globalMap = new HashMap<String,Object>();
File talendLogFile = new File("C:\\Softwares\\logFiles\\error.log");
Writer talendLogFileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(talendLogFile, true)));
globalMap.put("Logger", talendLogFileWriter);
((BufferedWriter) globalMap.get("Logger")).write("I'm Writing");
((BufferedWriter) globalMap.get("Logger")).close();
Is there any way I could perform both functionalities happening in last two lines in single line of code? I mean close BufferedWriter just after write.
Besides using try-with-resources, the real answer is: do not do it this way.
You see, you put a writer into a global map. That makes it available to the "whole" world that has access to that map. And next, some code intends to close the writer you added to that map.
But it seems that the writer itself is staying in the map. So other code can notice: the map has a logger/writer ... but how is that other code supposed to know if that logger/writer is still open, or was closed?
Having a logger/writer in that global map, but it can't be used globally, that is a contradiction in itself!
In other words: conceptually, what you are doing seems wrong. Either you add such a logger/writer to a global map, then all code that has access to that map should be able to use that logger/writer (without worrying "is it still open?"). Or, you do not put the logger/writer in such a global map.
Trivially, yes:
((BufferedWriter) globalMap.get("Logger")).write("I'm Writing"); ((BufferedWriter) globalMap.get("Logger")).close();
If you mean use a single method call to do both things, not unless you define a new method to do so.
You can try to use try-catch with resources. That mean resources will be automatically closed after try block will be done. You can read more here https://www.baeldung.com/java-try-with-resources
try(Writer talendLogFileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(talendLogFile, true)))) {
globalMap.put("Logger", talendLogFileWriter);
((BufferedWriter) globalMap.get("Logger")).write("I'm Writing");
}catch(Exception ignored){} //handle the exception if you want
The closest you can get is this, but as already mentiond by many others, there is no need to. It just complicates things:
try (BufferedWriter bw = (BufferedWriter) globalMap.get("Logger")) {
bw.write("I'm Writing");
}
Use try with resources which automatically closes the resource without needing to explicitly close it.

How to use tables and .txt in Java?

Im building a Car Rental program and what I want it to, for now, is:
Register a user
Register a car
using .txt files to store the data.
With the code I've written, I can register only a single car and user. Every time I run the register method for client or car, the last register is erased.
Can you help me with this? Also, later I'm going to implement a way to rent a car, but I don't know how to do that also, so if you have any ideas of how to do it, please tell me!
Also I intend to do it without SQL or such things.
This is the code I'm using to register a user (I'm using netbeans with JForm):
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
String nomeClient = txtNomeClient.getText();
String idClient = txtIdClient.getText();
File file = new File("clients.txt");
try {
PrintWriter output = new PrintWriter(file);
output.println(nomeClient);
output.println(idClient);
output.close();
JOptionPane.showMessageDialog(null, "Client registed!");
} catch (FileNotFoundException e) {
}
}
The problem is that you overwrite the existing file clients.txt, instead of appending to it by calling new PrintWriter(file). You can use the following code:
FileWriter fileWriter = new FileWriter(file, true);
PrintWriter output = new PrintWriter(fileWriter));
This way, you append the end of the file, see the constructor FileWriter(File file, boolean append). The documentation describes it perfectly:
Constructs a FileWriter object given a File object. If the second argument is true, then bytes will be written to the end of the file rather than the beginning.
The FileWriter is just used to open a file in append mode, as PrintWriter does not have a suitable constructor to do that directly. You could also write characters with it, but a PrintWriter allows for formatted output. From the documentation of FileWriter:
Convenience class for writing character files. The constructors of this class assume that the default character encoding and the default byte-buffer size are acceptable.
The PrintWriter uses the FileWriter passed in its constructor to append to the destination file, see here for a good explanation. As stated there, you could also use an FileOutputStream. There are multiple ways to do this.
Here is an example using a FileOutputStream and a BufferedWriter, which supports buffering and can reduce unnecessary writes that penalize performance.
FileOutputStream fileOutputStream = new FileOutputStream("clients.txt", true);
BufferedWriter bufferedWriter = new BufferedWriter(fileOutputStream);
PrintWriter printWriter = new PrintWriter(bufferedWriter);

Cannot properly close the text file

I have this code that copies an array elements into a text file, and after copying the files I have a button which opens the file i-copied.
try
{
print = new PrintWriter("C:\\Users\\Jofrank\\workspace\\Java\\src\\payroll\\report.txt");
print.println("EMPLOYEES PAYROLL RECORD AS OF "+dateFormat.format(date));
print.println();
for(int x=0;x<department.length;x++)
{
print.println("DEPARTMENT: "+department[x].toUpperCase());
print.println("\tPAYROLL PERIOD\tEMPLOYEE NUMBER\tNAME\tPAY RATE\tHOURS WORKED\tSALARY");
print.println();
for(int y=0;y<trans.length;y++)
{
if(trans[y] == null)
{
continue;
}
if(trans[y].getDepartment().equals(department[x]))
{
print.println("\t"+trans[y].getPayrollPeriod()+"\t"+trans[y].getEmpNo()+"\t\t"+trans[y].getName()+"\t"+trans[y].getPayRate()+"\t\t"+trans[y].getHoursWorked()+"\t\t"+String.format("%,.2f", (trans[y].getPayRate()*trans[y].getHoursWorked())));
total+=(trans[y].getPayRate()*trans[y].getHoursWorked());
}
}
print.println("\t\t\t\t\t\t\t\t\tTOTAL:\t"+String.format("%,.2f", total));
print.println();
total=0;
}
print.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
Unfortunately, My text file was not UPDATED unless i-close the system.
Is there a way that my text file will be updated automatically without CLOSING the system?
You can actually create a PrintWriter with autoFlush turned on:
print = new PrintWriter(new FileOutputStream
("C:\\Users\\Jofrank\\workspace\\Java\\src\\payroll\\report.txt"), true);
Here 2nd parameter is true. As per Javadoc:
autoFlush - A boolean; if true, the println, printf, or format
methods will flush the output buffer
That depens much on the system.
flush() usually should work, but this is all not garuanteed.
There are some embedded flash file system where you might call sync, too.
But for the first apporach try flush()
You need to empty your stream for it to be written to the file. As others have suggested, use .flush() to accomplish this without having to .close() your stream. Otherwise I believe .close() automagically calls .flush() for you to ensure your stream has been emptied and it's contents written to disk or wherever you are directing it.
In documentation it is said that PrintWriter does not flush lines automatically.
You may need to use different constructor for PrintWriter:
PrintWriter(File file)
but you have to open the file itself and then close it after writing is done.

Categories

Resources