I just wonder if I can use BufferedReader and BufferedInputStream together?
for example, I create a socket and read some data from server, assume I use default charset. Can I code like this?
Reader reader = new BufferedReader(
new InputStreamReader(
new BufferedInputStream(
socket.getInputStream)));
Or should I only use one of these two class at a time? Thanks for your help.
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 am using BufferedReader to get data fro ma url.
URL url = new URL("http://");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), "windows-1251"));
On some url's encoding is windows-1251 (cyrilyc) so i specified that in the reader. But on some ones, enconding is different, e.g KOI8-R Any way to get the data from both sources without using naother reader? I really can use only one here.
No, the BufferedReader cannot examine the Content-Enconding header. You have to supply that. Or use a library for encoding recognition/detection.
I am working with a html file.. I used html cleaner to clean the html file then the format is changed (All 'e's replaced by +®)... how can i correct that in java
Post some code on what you are doing. Here is an answer I got to a similar question
FileInputStream fis = new FileInputStream("filename");
BufferedReader reader = new BufferedReader(new InputStreamReader(fis, "UTF-16"));
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.
Can I easily convert InputStream to BufferedReader using Guava?
I'm looking for something like:
InputStream inputStream = ...;
BufferedReader br = Streams.newBufferedReader(inputStream);
I can open files using the Files.newReader(File file, Charset charset). That's cool and I want to do the same using the InputStream.
UPDATE:
Using CharStreams.newReaderSupplier seems to verbose for me. Correct me if I'm wrong, but in order to easily convert InputStream to BufferedReader using Guava I have to do something like that:
final InputStream inputStream = new FileInputStream("/etc/fstab");
Reader bufferedReader = new BufferedReader(CharStreams.newReaderSupplier(new InputSupplier<InputStream>(){
public InputStream getInput() throws IOException {
return inputStream;
}
}, Charset.defaultCharset()).getInput());
Of course I can create helper do sth like:
return new BufferedReader(new InputStreamReader(inputStream));
However I think that such helper should be offered by Guava IO. I can do such trick for File instance. Why cannot I for InputStream?
// Guava can do this
Reader r = Files.newReader(new File("foo"), charset);
// but cannot do this
Reader r = SomeGuavaUtil.newReader(inputStream, charset);
Correct me If I'm wrong but it seems to me like lack in the API.
No, there isn't anything quite like that in Guava. CharStreams is the general class for working with Readers and Writers and it has a method
InputSupplier<InputStreamReader> newReaderSupplier(
InputSupplier<? extends InputStream> in, Charset charset)
which could be useful with any kind of supplier of InputStreams.
Obviously, you can just write new BufferedReader(new InputStreamReader(in, charset)) or wrap that in your own factory method as well.
Edit:
Yes, you wouldn't want to use the InputSupplier version when you already have an InputStream. It's sort of like how it's a bad idea to make an Iterable that can actually only work once, such as one that wraps an existing Iterator or Enumeration or some such. In general, using InputSupplier requires thinking about how you do I/O a little different, such as thinking of a File as something that can act as a supplier of FileInputStreams. I've used InputSuppliers that wrap whole requests to a server and return the response content as an InputStream, enabling me to use Guava utilities to copy that to a file, etc.
In any case, I'm not entirely sure why CharStreams doesn't have a method to create a Reader from an InputStream other than perhaps they didn't feel it was needed. You may want to file an issue requesting this.