Does closing a Stream close the BufferedReader source? - java

From the docs:
Streams have a BaseStream.close() method and implement AutoCloseable,
but nearly all stream instances do not actually need to be closed
after use. Generally, only streams whose source is an IO channel (such
as those returned by Files.lines(Path, Charset)) will require closing.
Most streams are backed by collections, arrays, or generating
functions, which require no special resource management. (If a stream
does require closing, it can be declared as a resource in a
try-with-resources statement.)
When I create a Stream<String> using the lines() method on a BufferedReader as seen below, does closing the Stream also close the BufferedReader?
try (Stream<String> lines = new BufferedReader(new InputStreamReader(process.getInputStream())).lines()) {
// Do stuff
}
// Is the BufferedReader, InputStreamReader and InputStream closed?
Some really quick tests I've tried say no (the in field of the BufferedReader is not null), but then I'm confused by the following sentence, since this example is I/O as well, right?
Generally, only streams whose source is an IO channel (such
as those returned by Files.lines(Path, Charset)) will require closing.
If not, do I need to close both instances, or will closing the BufferedReader suffice?
Ideally, I'd like to return a Stream<String> from some method, without having the client worry about the readers. At the moment, I've created a Stream decorator which also closes the reader, but it's easier if that isn't necessary.

If you want to defer closing of the reader to the delivered Stream you need to invoke Stream.onClose():
static Stream<String> toStream(BufferedReader br){
return br.lines().onClose(asUncheckedAutoCloseable(br));
}
static Runnable asUncheckedAutoCloseable(AutoCloseable ac) {
return () -> {
try {
ac.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}

No, seems it doesn't. As the stream is created using
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
which doesn't pass any reference to the the BufferedReader

In your question you don't show how you create the Reader that is the argument of new BufferedReader(in). But from my own tests there is no reason to assume that the Stream closes this argument.
Doing the following should close everybody:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.stream.Stream;
public class SOPlayground {
public static void main(String[] args) throws Exception {
try (Reader in = new InputStreamReader(new FileInputStream(new File("/tmp/foo.html")));
BufferedReader reader = new BufferedReader(in);
Stream<String> lines = reader.lines()) {
lines.forEach(System.out::println);
}
}
}

Related

BufferedReader is closed when returned from method

I'm writing code to read a file and process it and I'm splitting logic into many small methods. So I have a method to read the file and return BufferedReader and another one to do logic with the returned BufferedReader object. But when I try to read lines from the BufferedReader object in the second method it gives me [java.io.IOException: Stream Closed].
The method I used to read the file and return BufferedReader
private static BufferedReader readFile(String file) {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
System.out.println(bufferedReader.readLine()); // this line is working successfully
return bufferedReader;
} catch (FileNotFoundException fileNotFoundException) {
fileNotFoundException.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
Any idea why the happens and how to solve it ?
You are using try-with-resources:
try (FileInputStream fileInputStream = new FileInputStream(file)) {
This line is creating a FileInputStream which can be used inside your try block. As soon as you leave your try block, the close() method will be called onto the stream. So if you return the stream or its BufferedReader, the stream will already be closed. You should not use try-with-resources or even better, return whatever you need from the stream instead of the stream itself.
Obviously, the problem here lies in the use of try-with-resources, and AutoCloseable interface. However, i would like to point out that the way you read the file is the "old fashioned" way. We now have the Files, Paths, and Stream classes to facilitate reading of files. this uses java NIO, returns a Stream and is better overall:
Files.lines(Paths.get(pathToFile))
additionally, nothing has to be closed here

Use of PrintWriter with streams of bytes

I'am testing the PrintWriter class which can handle streams of characters and streams of bytes. Everything went smooth when i tried with streams of characters, now i was testing it with streams of bytes and whenever i print what it reads it always displays null(exception). Here's the code:
package com.files.ex1;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
public class ex1 {
public static void main(String[] args) {
PrintWriter oPW;
try {
oPW = new PrintWriter(new ObjectOutputStream(new FileOutputStream("data.txt")));
oPW.write("1\n");
oPW.write("2\n");
oPW.write("3\n");
oPW.flush();
oPW.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
This is the class that tries to read and always prints null:
package com.files.ex1;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ex1_2 {
public static void main(String[] args) {
ObjectInputStream oOIS;
try {
oOIS = new ObjectInputStream(new FileInputStream("data.txt"));
String s = (String) oOIS.readObject();
System.out.println(s);
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (ClassNotFoundException e) {
System.out.println(e.getMessage());
}
}
}
Also what are the advantages of using this class? For streams of characters i can just use BuffedReadear or BufferedWriter to optimize reads or writes respectively, and it also has flush() method.
And what is the advantage of using PrintWriter with streams of bytes? Using ObjectOutputStream alone works when i try to do the operations above.
The reason you're getting null is because you're using readObject on ObjectInputString, but you haven't serialized any Java objects. ObjectInputString.readObject is to be used with ObjectOutputString.writeObject.
The PrintWriter docs state explicitly that
It does not contain methods for writing raw bytes, for which a program should use unencoded byte streams.
You should only use PrintWriter for text. It exposes helpful methods that you may be familiar with because System.out has the print interface.
You should only really use ObjectOutput/InputStream when writing and reading serialized Java Objects. The serialization format is binary data (unlike JSON/XML for example). These objects must implement the Serializable interface.
You can improve performance of writing and reading unencoded byte streams by use BufferedOutputStream and BufferedInputStream respectively.
In general, classes with suffix "Reader" and suffix "Writer" are for text encoded streams. They contain helpful methods for parsing strings and lines from text streams. They should never be used for transferring binary data.
In your example you're only writing text data to a file and reading that text data back, so use:
oPW = new PrintWriter(new FileOutputStream("data.txt"));
oPW.println("1");
for writing and
oOIS = new BufferedReader(new FileInputStream("data.txt"));
String s = oOIS.readLine(); // "1"
for reading.
If you were reading and writing binary data, you would do this instead:
os = new FileOutputStream("data.bin");
os.write(new byte[]{ 1, 2, 3 });
and read:
is = new FileInputStream("data.bin");
byte[] buf = new byte[3];
is.read(buf); // buf now equals {1, 2, 3}
If you were reading and writing Java objects, you would do this instead:
oos = new ObjectOutputStream(new FileOutputStream("data.bin"));
Foo foo = new Foo(...);
oos.writeObject(foo);
and read:
ois = new ObjectInputStream(new FileInputStream("data.bin"));
Foo foo = (Foo) ois.readObject();

How to unite data from several files in ONE buffer?

I'd like create one Stream with data from several files. How I can do it ? There are my java class. Or maybe I should using not BufferReader but other way ? Thanks !!
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.stream.Stream;
public class BuffReader {
public static void main(String[] args) throws FileNotFoundException {
File file1 = new File("src/page_1.txt");
File file2 = new File("src/page_2.txt");
File file3 = new File("src/page_3.txt");
BufferedReader bufferedReader = new BufferedReader(new FileReader(file1));
//*** I'd like get one bufferedReader with file1 + file2 + file3.
Stream<String> stream = bufferedReader.lines(); // get Stream
stream.forEach(e -> System.out.println(e)); // Working with Stream
}
}
You can create one Stream from the BufferedReader for each file, combine them into a stream, and then use the Stream#flatMap method to create a stream that is a concatenation of all these.
import java.util.function.Function;
import java.util.stream.Stream;
public class CombinedStreams
{
public static void main(String[] args)
{
Stream<String> stream0 = Stream.of("line0", "line1");
Stream<String> stream1 = Stream.of("line2", "line3");
Stream<String> stream2 = Stream.of("line4", "line5");
Stream<String> stream = Stream.of(stream0, stream1, stream2)
.flatMap(Function.identity());
stream.forEach(e -> System.out.println(e));
}
}
(Kudos to diesieben07 for the suggested improvement!)
If you don't need a BufferedReader and the Stream solution is enough, use that.
If you absolutely need a Reader you can use SequenceInputStream to concatenate the InputStreams and then create a BufferedReader from that.
The API is a little clunky since SequenceInputStream takes an Enumeration, so you would have to use one of the old collection types like Vector to construct it, but it works.

How to create and write a .Txt file in Java? [duplicate]

This question already has an answer here:
Java PrintWriter not working
(1 answer)
Closed 6 years ago.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class FileGenerator {
/**
* #param args
*/
public static void main(String[] args) {
File outputFile;
BufferedReader reader;
FileWriter fileWriter;
try {
outputFile = new File("test.txt");
outputFile.createNewFile();
fileWriter = new FileWriter(outputFile, false);
reader = new BufferedReader(new FileReader("template.txt"));
StringBuilder sb = new StringBuilder();
String line = reader.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = reader.readLine();
}
String everything = sb.toString();
fileWriter.write(everything);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
}
}
}
The fileWriter creates test.txt but the string inside of test.txt is empty. i want it doesnt happen empty. by the way you may say "String everything" can be empty. But it isnt. When i try without reader txt i mean "String everything = "some text", it happens same. it happens empty
The file is empty because the contents of everything are smaller than the operating systems and / or Java's I/O buffers, and the program ends without properly closing the file.
When you write something to a file, and you need to ensure that it is written without closing the file already, call flush().
Whenever you open an I/O resource, close it using close() after use. close() implies flushing the buffers.
Java 7 provides try-with-resources for that, like this:
try (FileWriter writer = new FileWriter("foo.txt")) {
writer.write("Hello, world!\n");
writer.flush();
// do more stuff with writer
} // <- closes writer implicitly as part of the try-with-resources feature
As suggested in the comments, you need to do fileWriter.close() in order to close the output stream. If it is a buffered writer, then closing it not necessary as explained here.
Is it necessary to close a FileWriter, provided it is written through a BufferedWriter?

File I/O producing gibberish on output

I'm learning File I/O using Java.
Following are my codes from two different Java files. One is "File" with the main class, the other is "FileWrite."
I was able to implement string input and output. But the output textfile has gibberish in the beginning and I am not sure why.
[File.Java]
package file;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class File {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("B:\\fileIn.txt")))
{
String stCurrent;
while ((stCurrent = br.readLine()) != null) {
System.out.println(stCurrent);
}
} catch (IOException e) {
e.printStackTrace();
}
FileWrite fW = new FileWrite();
fW.serializeAddress("Boston", "Canada");
}
}
[FileWrite.Java]
package file;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class FileWrite {
public void serializeAddress(String city, String country) {
try {
FileOutputStream fout = new FileOutputStream("B:\\address.txt");
ObjectOutputStream obOut = new ObjectOutputStream(fout);
obOut.writeUTF(city);
obOut.writeUTF(country);
obOut.close();
System.out.println("Output Done");
} catch(Exception ex) {
ex.printStackTrace();
}
}
}
Now, on "obOut.writeUTF(city); obOut.writeUTF(country);" I separated out two string inputs. Is there a way to combine them into one? As in obOut.writeUTF(city, counry) instead of two. Or is this only achievable through making these into an object?
[Update]
Imported a couple more and I tried
PrintStream ps = new PrintStream(new FileWriter("B:\\addressPS.txt"));
ps.println(city);
ps.println(country);
ps.close();
But with errors, any clue?
You are doing the right thing keeping them separate already. City and country are different fields.
A very common mistake is not making a distinction between binary and text files/socket streams. You are a mixing the two which will lead to confusion. I suggest you only sue text Writer/Reader or binary Input/OuptutStream unless you have a very clear idea of what you are doing.
In short if you what to write text use
PrintStream ps = new PrintStream(new FileWriter(textFileName));
ps.println(city);
ps.println(country);
ps.close();
writeUTF takes strings also, you don't have to create new object for city and county.
Cant you do obOut.writeUTF(city +" "+country); ?
The gibberish is because .writUTF() writes data in a modified UTF format which is mentioned in the javadocs.
An ObjectOutputStream is generally used to output OBJECTS but I suppose you can use it for strings as well. You can use the respective .readUTF() method in the ObjectInputStream class in order to read the data in your file back.
Also, you have tried to use the try-with-resources block which is new to Java SE7. You should NOT do it the way you have done so. You should do this instead:
try (FileReader fr = new FileReader("B:\\fileIn.txt"); BufferedReader br = new BufferedReader(fr);) {
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
Splitting the FileReader and the BufferedReader will allow Java SE7 to close both the streams with ease. The way you have done it, only the BufferedReader stream will get closed after the try block finishes.
By definition, ObjectOutputStream produces 'gibberish'. It's not intended for human consumption, it is a format used to write out objects so that you can read them back. You're not supposed to be able to make sense of the results in a text editor. To make human-readable content, just use an OutputStreamWriter or even a PrintWriter. In short, your last example is correct, and if you get errors, please edit your question to tell us what the errors are.

Categories

Resources