Hi I have a bit of confusion about the stream to use to write in a text file
I had seen some example:
one use the PrintWriter stream
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(fname)));
out.println(/*something to write*/);
out.close();
this instead use:
PrintStream out = new PrintStream(new FileOutputStream(fname));
out.println(/*something to write*/)
but which is the difference?both write in a file with the same result?
PrintWriter is new as of Java 1.1; it is more capable than the PrintStream class. You should use PrintWriter instead of PrintStream because it uses the default encoding scheme to convert characters to bytes for an underlying OutputStream. The constructors for PrintStream are deprecated in Java 1.1. In fact, the whole class probably would have been deprecated, except that it would have generated a lot of compilation warnings for code that uses System.out and System.err.
PrintWriter is for writing text, whereas PrintStream is for writing data - raw bytes. PrintWriter may change the encoding of the bytes to make handling text easier, so it might corrupt your data.
PrintWriter extends the class Writer, a class thinked to write characters, while PrintStream implements OutputStream, an interface for more generic outputs.
Related
If I were to create an InputStreamReader with the following code,
new InputStreamReader(anInputStream, "UTF-8")
I would have to catch UnsupportedEncodingException, which is reasonable. I can avoid this by using
new InputStreamReader(anInputStream, StandardCharsets.UTF_8)
which doesn't throw UnsupportedEncodingException as the charset is already known to be valid. All good so far.
Now enter its counterpart, the PrintWriter:
new PrintWriter("filename", StandardCharsets.UTF_8)
doesn't compile because the PrintWriter constructor doesn't take a Charset argument. I can do this:
new PrintWriter("filename", StandardCharsets.UTF_8.name())
but then I can't avoid having to catch UnsupportedEncodingException, even though the charset name has just come from a valid charset.
The StandardCharsets utility class was added later on in Java's lifetime, and when Sun added it, they also added an overload to the InputStreamReader constructor. Why did they add an overload to InputStreamReader but not PrintWriter?
Is there another class I can use instead, which takes a charset instead of a charset name?
The counterpart to InputStreamReader is not PrintWriter.
Use OutputStreamWriter instead.
If you want to use PrintWriter, it's possible to use PrintWriter(new OutputStreamWriter(anOutputStream, StandardCharsets.UTF_8));
The counterpart of java.io.InputStreamReader is java.io.OutputStreamWriter, not java.io.PrintWriter.
That said, you can create the PrintWriter safely like this:
Reader reader = new InputStreamReader(anyOutputStream, StandardCharsets.UTF_8);
Writer writer = new OutputStreamWriter(anyInputStream, StandardCharsets.UTF_8);
PrintWriter printWriter = new PrintWriter(writer);
but then I can't avoid having to catch UnsupportedEncodingException, even though the charset name has just come from a valid charset.
Which makes sense, right? Since it's still a String.
As suggested by Stewart, using the java.io.OutputStreamWriter would be the way to go.
new PrintWriter(new OutputStreamWriter(anOutputStream, StandardCharsets.UTF_8), isAutoFlush)
I want to pipe JSP PrintWriter out to another support class that takes InputStream or Writer as argument. I wonder if it's possible to simplify the process.
Of course I can write the output to a file, then use InputStream to read that file.
The "other" end of the JSP-provided PrintWriter is connected to the client (through the network, of course). You could create a new PrintWriter, pipe that to the support class and have the support class' output written to the original JSP PrintWriter.
Are PrintWriter and FileWriter in Java the same and no matter which one to use? So far I have used both because their results are the same. Is there some special cases where it makes sense to prefer one over the other?
public static void main(String[] args) {
File fpw = new File("printwriter.txt");
File fwp = new File("filewriter.txt");
try {
PrintWriter pw = new PrintWriter(fpw);
FileWriter fw = new FileWriter(fwp);
pw.write("printwriter text\r\n");
fw.write("filewriter text\r\n");
pw.close();
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
According to coderanch.com, if we combine the answers we get:
FileWriter is the character representation of IO. That means it can be used to write characters. Internally FileWriter would use the default character set of the underlying OS and convert the characters to bytes and write it to the disk.
PrintWriter & FileWriter.
Similarities
Both extend from Writer.
Both are character representation classes, that means they work with characters and convert them to bytes using default charset.
Differences
FileWriter throws IOException in case of any IO failure, this is a checked exception.
None of the PrintWriter methods throw IOExceptions, instead they set a boolean flag which can be obtained using checkError().
PrintWriter has an optional constructor you may use to enable auto-flushing when specific methods are called. No such option exists in FileWriter.
When writing to files, FileWriter has an optional constructor which allows it to append to the existing file when the "write()" method is called.
Difference between PrintStream and OutputStream: Similar to the explanation above, just replace character with byte.
PrintWriter has following methods :
close()
flush()
format()
printf()
print()
println()
write()
and constructors are :
File (as of Java 5)
String (as of Java 5)
OutputStream
Writer
while FileWriter having following methods :
close()
flush()
write()
and constructors are :
File
String
Link: http://www.coderanch.com/t/418148/java-programmer-SCJP/certification/Information-PrintWriter-FileWriter
Both of these use a FileOutputStream internally:
public PrintWriter(File file) throws FileNotFoundException {
this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))),
false);
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
but the main difference is that PrintWriter offers special methods:
Prints formatted representations of
objects to a text-output stream. This
class implements all of the print
methods found in PrintStream. It does
not contain methods for writing raw
bytes, for which a program should use
unencoded byte streams.
Unlike the PrintStream class, if
automatic flushing is enabled it will
be done only when one of the println,
printf, or format methods is invoked,
rather than whenever a newline
character happens to be output. These
methods use the platform's own notion
of line separator rather than the
newline character.
A PrintWriter has a different concept of error handling. You need to call checkError() instead of using try/catch blocks.
PrintWriter doesn't throw IOException.You should call checkError() method for this purpose.
The java.io.PrintWriter in Java5+ allowed for a convenience method/constructor that writes to file.
From the Javadoc;
Creates a new PrintWriter, without automatic line flushing, with the specified file. This convenience constructor creates the necessary intermediate OutputStreamWriter, which will encode characters using the default charset for this instance of the Java virtual machine.
just to provide more info related to FLUSH and Close menthod related to FileOutputStream
flush() ---just makes sure that any buffered data is written to disk flushed compltely and ready to write again to the stream (or writer) afterwards.
close() ----flushes the data and closes any file handles, sockets or whatever.Now connection has been lost and you can't write anything to outputStream.
The fact that java.io.FileWriter relies on the default character encoding of the platform makes it rather useless to me. You should never assume something about the environment where your app will be deployed.
I have several output listeners that are implementing OutputStream.
It can be either a PrintStream writing to stdout or to a File, or it can be writing to memory or any other output destination; therefore, I specified OutputStream as (an) argument in the method.
Now, I have received the String. What is the best way to write to streams here?
Should I just use Writer.write(message.getBytes())? I can give it bytes, but if the destination stream is a character stream then will it convert automatically?
Do I need to use some bridge streams here instead?
Streams (InputStream and OutputStream) transfer binary data. If you want to write a string to a stream, you must first convert it to bytes, or in other words encode it. You can do that manually (as you suggest) using the String.getBytes(Charset) method, but you should avoid the String.getBytes() method, because that uses the default encoding of the JVM, which can't be reliably predicted in a portable way.
The usual way to write character data to a stream, though, is to wrap the stream in a Writer, (often a PrintWriter), that does the conversion for you when you call its write(String) (or print(String)) method. The corresponding wrapper for InputStreams is a Reader.
PrintStream is a special OutputStream implementation in the sense that it also contain methods that automatically encode strings (it uses a writer internally). But it is still a stream. You can safely wrap your stream with a writer no matter if it is a PrintStream or some other stream implementation. There is no danger of double encoding.
Example of PrintWriter with OutputStream:
try (PrintWriter p = new PrintWriter(new FileOutputStream("output-text.txt", true))) {
p.println("Hello");
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
OutputStream writes bytes, String provides chars. You need to define Charset to encode string to byte[]:
outputStream.write(string.getBytes(Charset.forName("UTF-8")));
Change UTF-8 to a charset of your choice.
You can create a PrintStream wrapping around your OutputStream and then just call it's print(String):
final OutputStream os = new FileOutputStream("/tmp/out");
final PrintStream printStream = new PrintStream(os);
printStream.print("String");
printStream.close();
By design it is to be done this way:
OutputStream out = ...;
try (Writer w = new OutputStreamWriter(out, "UTF-8")) {
w.write("Hello, World!");
} // or w.close(); //close will auto-flush
Wrap your OutputStream with a PrintWriter and use the print methods on that class. They take in a String and do the work for you.
You may use Apache Commons IO:
try (OutputStream outputStream = ...) {
IOUtils.write("data", outputStream, "UTF-8");
}
IOUtils.write(String data, OutputStream output, String encoding)
An OutputStream obj can be connected into a PrintWriter obj directly, e.g.,
//either is OK
new PrintWriter(socket.getOutputStream());
new PrintWriter(new OutputStreamWriter(socket.getOutputStream()));
But in the case of an InputStream obj, it must be connected to a BufferedReader obj through an InputStreamReader obj, that is,
new BufferedReader(new InputStreamReader(socket.getInputStream())); //OK
new BufferedReader(socket.getInputStream()); //doesnt work
Is there any reason for this inconsistency of API design?
There isn't any inconsistency... you should be comparing BufferedReader and BufferedWriter. They exist to wrap other Readers and Writers respectively.
The basic reason for that is that different types of Readers and Writers may have different ways of being initialized and different ways of functioning, not necessarily wrapping an InputStream or OutputStream at all. In your example of a BufferedReader wrapping an InputStreamReader, InputStreamReader can (and generally should) be initialized with both an InputStream and a Charset. Should BufferedReader have an overload for that, when its only job is to provide buffering?
Java introduced Reader and Writer hierarchy (java 1.1 I think) when Input and output stream classes were already in use. Therefore using a bridge pattern they allow you to have stream classes passed into reader classes.
Further for writer also PritnerWriter is directly the bridge class which is equivalent to InputStreamReader. You will see the same thing for BufferedWriter too
For more info read up http://www.codeguru.com/java/tij/tij0114.shtml
The BufferedReader is probably just decorating the InputReader being passed in. It makes no sense for a BufferedReader to accept a class it can't decorate, like an InputStream.