I am really confused about the purpose of various io classes, for example, If we have BufferedWriter, why we need a PrintWriter?
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = null;
while(s=br.readline()!=null) {
PrintWriter fs = new PrintWriter(new FileWriter(file));
fs.println(s);
}
if the BufferedWriter can not help? I just do not understand the difference between these io classes, can someone explain me?
They have nothing to do with each other. In all truth, I rarely use PrintWriter except to convert System.out temporarily. But anyway.
BufferedWriter, like BufferedReader/BufferedInputStream/BufferedOutputStream merely decorates the enclosed Writer with a memory buffer (you can specify the size) or accept a default. This is very useful when writing to slow Writers like network or file based. (Stuff is committed in memory and only occasionally to disk for example) By buffering in memory the speed is greatly increased - try writing code that writes to say a 10 mb file with just FileWriter and then compare to the same with BufferedWriter wrapped around it.
So that's BufferedWriter. It throws in a few convenience methods, but mostly it just provides this memory buffer.
PrintWriter mostly is a simple decorator that adds some specific write methods for various types like String, float, etc, so you don't have to convert everything to raw bytes.
Edited:
This already has come up
The PrintWriter is essentially a convenience class. If you want to quickly and easily blast out a line of text to e.g. a log file, PrintWriter makes it very easy.
Three features:
The print and println methods will take any data type and do the conversion for you. Not just String.
The relatively new format method is worth its weight in gold. Now it's as simple in Java as in C to output a line of text with C-style format control.
The methods never throw an exception! Some programmers are horrified at the possibility of never hearing about things going wrong. But if it's a throwaway program or doing something really simple, the convenience can be nice. Especially if output is to System.out or System.err which have few ways of going wrong.
The main reason to use the PrintWriter is to get access to the printXXX methods (like println(int)). You can essentially use a PrintWriter to write to a file just like you would use System.out to write to the console.
A BufferedWriter is an efficient way to write to a file (or anything else) as it will buffer the characters in Java memory before writing to the file.
Related
I need to write characters to a file or to standard output. And I am curious if it could be done with one method.
Now I have something like this:
OutputStream out;
if(toConsole)
out = System.out;
else
out = new FileOutputStream(file);
write(out);
}
void write (OutputStream str){
....
str.write(string);
But it is a problem that I am using (in case when "str" is System.out) write instead print?
(print java doc: "string's characters are converted into bytes according to the platform's default character encoding")
In case if I would use PrintWriter(or PrintStream) as a parameter then i cannot use BufferedWriter and writing to the file would be slower.
It is possible to use a same code (and same methods) for writing to a file and to System.out?
(This is for my school project so I want it to be a "pure" and fully correct)
What you're trying to accomplish, is to treat the fileoutput and the consoleoutput the same. This is possible, because System.out is a PrintStream, and you can create a PrintStream for a file like this
new PrintStream(yourFile)
or insert a BufferedOutputStream in between
new PrintStream(new BufferedOutputStream(new FileOutputStream(yourFile))).
Note that this is not needed, because PrintStream does buffer its output itself.
I would create a variable (global or not), representing the current output.
This might be a PrintStream, either System.out, or a PrintStream around a FileOutputStream, whatever you desire. You would then pass this stream to the write method or call the print methods on it directly.
The advantage is that you can easily switch this without much code modification, you can redirect it wherever you wan't. It's no problem to redirect it to a file and System.out! You wouldn't get that pure flexibility with the way you're writing the method currently.
You could (not saying you should), also redirect System.out directly, using System.setOut. This however is bad style, because it is quite uncommon and might confuse everyone else, if they have not seen the call to System.setOut.
System.out is an object of type PrintStream. So yes, you can write to
System.out and/or to another file using exactly the same methods. Just
construct a PrintStream object and direct it to your file. So declare
your out variable as PrintStream to start with.
See also:
http://docs.oracle.com/javase/7/docs/api/java/lang/System.html
http://docs.oracle.com/javase/7/docs/api/java/io/PrintStream.html
I have the following methods that creates and writes to that file.
// Create the file and the PrintWriter that will write to the file
private static PrintWriter createFile(String fileName){
try{
// Creates a File object that allows you to work with files on the hardrive
File listOfNames = new File(fileName);
PrintWriter infoToWrite = new PrintWriter(new BufferedWriter(
new FileWriter(listOfNames);
return infoToWrite;
}
// You have to catch this when you call FileWriter
catch(IOException e){
System.out.println("An I/O Error Occurred");
// Closes the program
System.exit(0);
}
return null;
}
The program works fine, even if I dont have bufferedWriter and FileWriter like below. how does they two objects help in making the writing process better? I can avoid creating two objects in this case.
PrintWriter infoToWrite = new PrintWriter((listOfNames);
BufferedWriter
In general, a Writer sends its output immediately to the underlying
character or byte stream. Unless prompt output is required, it is
advisable to wrap a BufferedWriter around any Writer whose write()
operations may be costly, such as FileWriters and OutputStreamWriters.
If you're writing large blocks of text at once (like entire lines)
then you probably won't notice a difference. If you have a lot of code
that appends a single character at a time, however, a BufferedWriter
will be much more efficient.
you may refer to the API document and you'll find the difference:
BufferedWriter:Writes text to a character-output stream, buffering characters so as to provide for the efficient writing of single characters, arrays, and strings.
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. To specify these values yourself, construct an OutputStreamWriter on a FileOutputStream.
if you want to create a file, the FileWriter will be better.
I am new to Java. I want to learn to use GZIPstreams. I already have tried this:
ArrayList<SubImage>myObject = new ArrayList<SubImage>(); // SubImage is a Serializable class
ObjectOutputStream compressedOutput = new ObjectOutputStream(
new BufferedOutputStream(new GZIPOutputStream(new FileOutputStream(
new File("....")))));
compressedOutput.writeObject(myObject);
and
ObjectInputStream compressedInput = new ObjectInputStream(
new BufferedInputStream(new GZIPInputStream(new FileInputStream(
new File("....")))));
myObject=(ArrayList<SubImage>)compressedInput.readObject();
When the program writes myObject to a file without throwing any exception, but when it reaches the line
myObject=(ArrayList<SubImage>)compressedInput.readObject();
it throws this exception:
Exception in thread "main" java.io.EOFException: Unexpected end of ZLIB input stream
How can I solve this problem?
You have to flush and close your outputstream. Otherwhise, at least, the BufferedOutputStream will not write everything to the file (it does in big chucks to avoid penalizing performance).
If you call compressedOutput.flush() and compressedOutput.close() it will suffice.
You can try writing a simple string object and checking if the file is well written.
How? If you write a xxx.txt.gz file you can open it with your preferred zip app and look at the xxx.txt. If the app complains, then the content is not full written.
Extended answer to a comment: compressing even more the data
Changing serialization
You could change the standard serialization of SubImage object if it's an object of your own. Check java.io.Serializable javadoc to know how to do it. It's pretty straightforward.
Writing just what you need
Serialization has the drawback that needs to write "it's a SubImage" just before every instance you write. It's not necessary if you know what's going to be there beforehand. So you could try to serialize it more manually.
To write your list, instead of writing an object write directly the values that conform your list. You will need just a DataOutputStream (but ObjectOutputStream is a DOS so you can use it anyway).
dos.writeInt(yourList.size()); // tell how many items
for (SubImage si: yourList) {
// write every field, in order (this should be a method called writeSubImage :)
dos.writeInt(...);
dos.writeInt(...);
...
}
// to read the thing just:
int size = dis.readInt();
for (int i=0; i<size; i++) {
// read every field, in the same order (this should be a method called readSubImage :)
dis.readInt(...);
dis.readInt(...);
...
// create the subimage
// add it to the list you are recreating
}
This method is more manual but if:
you know what's going to be written
you will not need this kind of serialization for many types
it's pretty affordable and definitively more compressed than the Serializable counterpart.
Have in mind that there are alternative frameworks to serialize objects or create string messages (XStream for xml, Google Protocol Buffers for binary messages, and so on). That frameworks could work directly to binary or writing a string that could be then written.
If your app will need more on this, or just curious, maybe you should look at them.
Alternative serialization frameworks
Just looked in SO and found several questions (and answers) addressing this issue:
https://stackoverflow.com/search?q=alternative+serialization+frameworks+java
I've found that XStream is pretty easy and straightforward to use. And JSON is a format pretty readable and succint (and Javascript compatible which could be a plus :).
I should go for:
Object -> JSON -> OutputStreamWriter(UTF-8) -> GZippedOutputStream -> FileOutputStream
I have always been slightly confused with the amount of different IO implementations in Java, and now that I am completely stuck in my project development, I was taking my time to read up on useful stuff meanwhile.
I have realized that there is no newbie-friendly comparison (apart from short explanation at API for Writer class) between the different subclasses of the Writer class. So I figured I'd fire away the question, what are those different subclasses good for?
For example, I usually use a FileWriter wrapped with a BufferedWriter for my outputs to files but I have always been irritated by the fact that there is no println() like method, and one has to use newLine() every second line (to make the output human readable). PrintWriterhas the println() method but no constructor that supports appending however...
I'd really appreciate if you could give me your two cents from your experience, or a nice guide/how-to you might have stumbled upon.
EDIT: Thanks for the replies everyone, I really appreciate the info passed on here. It's a bit unfortunate that the whole append() thing ended up being in focus, it merely meant it as an example. My question was mostly referring to the need and use of all the different implementations, which I guess was mentioned somewhat in a couple of the answers.
It's hard to pick one answer as accepted, since there are three really solid answers, each has contributed to my understanding of the problem. I am gonna have to go with Anon, this time as he's got the least amount of rep. points (I presume he's new on SO). He's 15 answers some of which are really well formulated, and 0 questions asked. Good contribution I'd say, and that is worth promoting.
That being said, ColinD and Jay also provided really good answers, and have pointed out interesting ideas. Especially Jay's comment about Java automatically wrapping a BufferedWriter was worth noting. Thanks again guys, really appreciated!
The java.io classes generally follow the Decorator pattern. So, while PrintWriter does not have the specific constructor you might want, it does have a constructor that takes another Writer, so you can do something like the following:
FileOutputStream fos = null;
try
{
fos = new FileOutputStream("foo.txt");
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(fos, "UTF-8")));
// do what you want to do
out.flush();
out.close();
}
finally
{
// quietly close the FileOutputStream (see Jakarta Commons IOUtils)
}
As a general usage note, you always want to wrap a low-level Writer (eg FileWriter or OutputStreamWriter) in a BufferedWriter, to minimize actual IO operations. However, this means that you need to explicitly flush and close the outermost Writer, to ensure that all content is written.
And then you need to close the low-level Writer in a finally block, to ensure that you don't leak resources.
Edit:
Looking at MForster's answer made me take another look at the API for FileWriter. And I realized that it doesn't take an explicit character set, which is a Very Bad Thing. So I've edited my code snippet to use a FileOutputStream wrapped by an OutputStreamWriter that takes an explicit character set.
FileWriter is generally not an acceptable class to use. It does not allow you to specify the Charset to use for writing, which means you are stuck with whatever the default charset of the platform you're running on happens to be. Needless to say, this makes it impossible to consistently use the same charset for reading and writing text files and can lead to corrupted data.
Rather than using FileWriter, you should be wrapping a FileOutputStream in an OutputStreamWriter. OutputStreamWriter does allow you to specify a charset:
File file = ...
OutputStream fileOut = new FileOutputStream(file);
Writer writer = new BufferedWriter(new OutputStreamWriter(fileOut, "UTF-8"));
To use PrintWriter with the above, just wrap the BufferedWriter in a PrintWriter:
PrintWriter printWriter = new PrintWriter(writer);
You could also just use the PrintWriter constructor that takes a File and the name of a charset:
PrintWriter printWriter = new PrintWriter(file, "UTF-8");
This works just fine for your particular situation, and actually does the exact same thing as the code above, but it's good to know how to build it by wrapping the various parts.
The other Writer types are mostly for specialized uses:
StringWriter is just a Writer that can be used to create a String. CharArrayWriter is the same for char[].
PipedWriter for piping to a PipedReader.
Edit:
I noticed that you commented on another answer about the verbosity of creating a writer this way. Note that there are libraries such as Guava that help reduce the verbosity of common operations. Take, for example, writing a String to a file in a specific charset. With Guava you can just write:
Files.write(text, file, Charsets.UTF_8);
You can also create a BufferedWriter like this:
BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8);
PrintWriter doesn't have a constructor that takes an "append" parameter, but FileWriter does. And it seems logical to me that that's where it belongs. PrintWriter doesn't know if you're writing to a file, a socket, the console, a string, etc. What would it mean to "append" on writes to a socket?
So the right way to do what you want is simply:
PrintWriter out=new PrintWriter(new BufferedWriter(new FileWriter(myfile, append)));
Interesting side note: If you wrap an OutputStream in a PrintWriter, Java automatically inserts a BufferedWriter in the middle. But if you wrap a Writer in a PrintWriter, it does not. So nothing is gained by saying:
PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(myfile))));
Just leave off the BufferedWriter and the OutputStreamWriter, you get them for free anyway. I have no idea if there is some good reason for the inconsistency.
It's true that you can't specify a character encoding in a FileWriter as ColinD notes. I don't know that that makes it "unacceptable". I almost always am perfectly happy to accept the default encoding. Maybe if you're using a language other than English this is an issue.
The need to wrap Writers or OutputStreams in layers was confusing to me when I first started using Java. But once you get the hang of it, it's no big deal. You just have to bend your mind into the write framework. Each writer has a function. Think of it like, I want to print to a file, so I need to wrap a FileWriter in a PrintWriter. Or, I want to convert an output stream to a writer, so I need an OutputStreamWriter. Etc.
Or maybe you just get used to the ones you use all the time. Figure it out once and remember how you did it.
You can create an appending PrintWriter like this:
OutputStream os = new FileOutputStream("/tmp/out", true);
PrintWriter writer = new PrintWriter(os);
Edit: Anon's post is right about both using a BufferedWriter in between and specifying the encoding.
What is the difference between using a BufferedReader around the StringReader in the following code vs using the StringReader only? By loading up the DOM in line 2 of both examples, it seems like the BufferedReader is not necessary?
InputSource is = new InputSource(new StringReader(html));
Document dom = XMLResource.load(is).getDocument();
VS
InputSource is = new InputSource(new BufferedReader(new StringReader(html)));
Document dom = XMLResource.load(is).getDocument();
In this particular case, I see no benefit. In general there are two benefits:
The oh-so-handy readLine() method is only defined in BufferedReader rather than Reader (irrelevant here)
BufferedReader reduces IO where individual calls to the underlying reader are potentially expensive (i.e. fewer chunky calls are faster than lots of little ones) - again, irrelevant for StringReader
Cut and paste fail?
EDIT: My original answer below. The below isn't relevant in this case, since the buffered reader is wrapping a StringReader, which wraps a String. So there's no buffering to be performed, and the BufferedReader appears to be redundant. You could make an argument for using best/consistent practises, but it would be pretty tenuous.
Possibly the result of a copy/paste, or perhaps an IDE-driven refactor too far!
BufferedReader will attempt to read in a more optimal fashion.
That is, it will read larger chunks of data in one go (in a configurable amount), and then make available as required. This will reduce the number of reads from disk (etc.) at the expense of some memory usage.
To quote from the Javadoc:
In general, each read request made of
a Reader causes a corresponding read
request to be made of the underlying
character or byte stream. It is
therefore advisable to wrap a
BufferedReader around any Reader whose
read() operations may be costly, such
as FileReaders and InputStreamReaders
The BufferedReader version was copied from some code that used to read from a FileReader?