BufferedReader#readLine() hangs even though a line has been read - java

Updated Question (to be more clear):
Is there a way to design the InputStream below such that BufferedReader#readLine() will return after reading the new line character?
In the example below, readLine() hangs forever even though the reader has read a new line because (presumably) it is waiting for the buffer to fill up. Ideally, readLine() would return after reading the new line character.
I know something like what I want is possible, because when you read from System.in using BufferedReader#readLine(), it does not wait for the buffer to fill up before returning.
import java.io.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class Example {
private static final class MyInputStream extends InputStream {
public final BlockingQueue<String> lines = new LinkedBlockingQueue<>();
private InputStream current = null;
#Override
public int read() throws IOException {
try {
if(current == null || current.available() == 0)
current = new ByteArrayInputStream(lines.take().getBytes("UTF-8"));
return current.read();
}
catch(InterruptedException ex) {
return -1;
}
}
}
public static void main(String[] args) throws Exception {
MyInputStream myin = new MyInputStream();
myin.lines.offer("a line\n");
BufferedReader in = new BufferedReader(new InputStreamReader(myin));
System.out.println(in.readLine());
}
}
Also, if there is a better way to send a string to an InputStream, I'm open to suggestions.
Accepted Solution:
Based on a suggestion from Sotirios Delimanolis in one of the comments on his solution, I'm just going to used a PipedInputStream instead. I've coupled it to a PipedOutputStream, and BufferedReader#readLine() returns immediately as long as I call PipedOutputStream#flush() after sending a string that contains a new line character.

After updated question, the only way to get the BufferedReader to stop reading after the new line character is to set the buffer size to 1, which completely removes the need for a BufferedReader.
You'll have to write your own implementation.
A BufferedReader reads more bytes than required. In your case, that means it will read further than the new line character. For example, with the Oracle JVM, it will attempt to read 8192 bytes. Through your inheritance hierarchy, this
System.out.println(in.readLine());
will attempt to invoke your read() method 8192 times.
The first 6 calls will return a value, one for each of the characters in your String's byte array. The next one, will see
if(current == null || current.available() == 0)
current = new ByteArrayInputStream(lines.take().getBytes("UTF-8"));
and current.available() will return 0 since the ByteArrayInputStream has been fully consumed. It will then attempt to take from the BlockingQueue and block indefinitely.

Also, if there is a better way to send a string to an InputStream, I'm open to suggestions.
Well, instead of an InputStream you can try a BufferedReader, with something that looks like this:
public int read(String directory) throws Exception{
String line = "";
File file = new File(directory);
FileReader fr = new FileReader(file);
BufferedReader br = new BufferedReader(fr);
do{
lines.add(br.readLine());
while(br.readLine() != null);
br.close();
return Integer.parseInt(line);
}

Related

BufferedReader reads just one line in an multiple line file

I tried to archive that a multiline file will be read from an BufferedReader. But this BufferedReader reads just one line and exiting his while(). Before he can read this, another method of the same class should've been written in this file (not at the same time), mostly more than one line. The file contains different types of variables, such as int[], int, double[], String. At the end of one object, or nearly just the data that I've to collect that I can re-calculate the whole object, the ObjectOutputStream pastes "\n". I just write parsed Strings in this file.
In my case, it's a workaround for the ObjectInputStream, cause this stream throws an EOFException every time. For those who don't know the EOFException: it will be thrown if the reader reaches end of file while reading.
I tried to:
set the input string for the BufferedReader to another line
.close() the Reader and make it new
set while(1)
write other Datatypes, such as the whole Object
but all without any changes. The BufferedReader reads just one line and the ObjectInputStream throws EOFException.
LinkedList<SomeAnotherSelfMadeClass> list;
File file = new File(fullPath) // fullPath = absolute path to the file
FileInputStream fileInputStream;
BufferedReader bufferedReader;
public static LinkedList<SomeAnotherSelfMadeClass> readFile()
{
list = new LinkedList<SomeAnotherSelfMadeClass>();
fileInputStream = new FileInputStream(file); // could be FileReader
bufferedReader = new BufferedReader(fileInputStream);
String helper, anotherHelper;
while ((helper = bufferedReader.readLine()) != null)
{
while ((anotherHelper = scanner.hasNext()) != null)
// here's some code with scanner-things, it shouldn't be necessary to
// know. In fact the scanner help to gather the data from the file and
// create an object of SomeAnotherSelfMadeCLass and put it into the list
}
bufferedReader.close();
fileInputStream.close();
return list;
}
What can I do that I can read all lines of the file and re-calcuate my objects that are pasted in there?
I don't know either; it is better to work with the ObjectInputStream or with the BufferedReader? What can I do that the ObjectInputStream don't throws the EOFException (every time I worked with the ObjectInputStream I wrote the whole Object via ObjectOutputStream)?
P.S.: I don't have internet atm at home, so it could take a while that I'm able to answer.
Try with this structure of code..
BufferedReader objReader = null;
public static LinkedList<SomeAnotherSelfMadeClass> readFile()
{
list = new LinkedList<SomeAnotherSelfMadeClass>();
try {
objReader = new BufferedReader(new FileReader(fullPath));
while ((helper= objReader.readLine()) != null) {
...........
System.out.println(helper);//just for checking
while ((anotherHelper = scanner.hasNextLine()) != null){
.....
....
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (objReader != null)
objReader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
I'm a little idiot, you have to know.
The second while() had the condition (anotherHelper = scanner.next()) != null, not that what I stated before.
But I managed to get another outputs, even I tried this before (it seems that I'd misstyped at any point);
I set the first while() to true, test helper to break out of the while() and deleted the second while:
while(true)
{
helper = bufferedReader.readLine();
if (helper.equals(null))
break;
// making things with the scanner
}
It seems that the compiler had a problem with this double-while. And optimized it wrong; I think he made
while (((helper = bufferedReader.readLine() != null) && (helper = scanner.nextLine()) != null)
out of this peace of code. That would explain why it only run once and returns true if I test it with System.out.println(scanner.hasNext(); and System.out.println(scanner.hasNextLine(); BEFORE the second while, but in it he returns not even false.

Is it incorrect to open a file for writing before it has been closed for reading?

I am refactoring a small tool which needs to iterate over a list of files and modify them on the fly.
At the moment it performs the modification operation in one method, which means it reads the file to memory, modifies the content within memory, and writes that content back to the same file location.
It is doing so all within a couple of try-with-resource statements. However, this means that the 'open for write' gets done before the read is closed.
I provide here below a small approximation (see method "correctTxt").
To test that, please create a file "FileQuestion.txt"
with text such as
The quick brown elephant jumps over the lazy dog
public class Demo
{
public static void main(String[] args) throws Exception
{
final File txtFile = new File("FileQuestion.txt");
correctTxt(txtFile);
}
static void correctTxt(File txtFile) throws IOException
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader (new BufferedInputStream(new FileInputStream(txtFile))))) {
String line = reader.readLine();
if (line!=null) {
line = line.replace("elephant", "fox");
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(txtFile))) {
bos.write(line.getBytes());
bos.flush();
}
}
}
}
}
It works. It is all done in a single process (single thread).
The question is,
Is it fundamentally incorrect to perform the write operation before the close of the read, in the way that is done in the method correctTxt ?
Note: It is not intended, after the first read, that any further read be done.
Good question. I'd say it's probably technically not a problem, but... I see is that the scope of the try-with is unnecessarily big and if you would reduce the scope to where it's needed, you wouldn't even be in this situation.
See this version of the correctTxt with minimized try-with scopes
static void correctTxt(File txtFile) throws IOException {
String line;
try (BufferedReader reader = new BufferedReader(new InputStreamReader (new BufferedInputStream(new FileInputStream(txtFile))))) {
line = reader.readLine();
}
if (line!=null) {
line = line.replace("elephant", "fox");
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(txtFile))) {
bos.write(line.getBytes());
bos.flush();
}
}
}

Java LineNumberReader reset to beginning

I want to read an InputStream in two passes, line by line. I use the following code for the first pass:
LineNumberReader reader = new LineNumberReader(new InputStreamReader(inputStream));
String line;
String eventId = null;
Set<Integer> artistIds = new HashSet<Integer>();
while((line = reader.readLine())!=null) {
// process first pass
}
// how do I reset reader so that I can read from the beginning again?
There is a reset() method available but it resets to the last mark in the file. I don't quite understand what that means. Can I use mark and reset to achieve the reset to beginning behavior? Something like
LineNumberReader reader = new LineNumberReader(new InputStreamReader(inputStream));
reader.mark(0); // mark at the 0th position
// process first pass: repeated calls to readline() until EOF
reader.reset(); // reset to 0th position??
// process second pass
While testing at my local machine, I was reader.close()-ing before the second pass and it worked. However, when I do this in HDFS, reader.close() probably closes the HDFS InputStream too and I get a java.io.IOException: Stream closed exception.
Mark and reset work, but don't call .mark(0) that sets the read ahead limit to 0 which means .reset() won't work reliably if you read more than 0 bytes.
EDIT: .mark() marks the current location in the stream. Unlike C++ where you can .seek() the beginning or end of a file and offsets, Java streams only allow you to mark a current location and then go back to it with .reset(). This can go "back to the beginning" but only if it was marked before processing started.
Try this:
import java.io.*;
public class StreamTwice
{
public static void printLines(LineNumberReader r) throws IOException
{
String line;
while( (line = r.readLine()) != null )
System.out.println(line);
System.out.println();
}
public static void main(String []args) throws Exception
{
ByteArrayInputStream s = new ByteArrayInputStream(
"one\ntwo\nthree".getBytes()
);
LineNumberReader r = new LineNumberReader(new InputStreamReader(s));
r.mark(5000); // more than the number of bytes being read.
// this is the read ahead limit.
printLines(r);
r.reset(); // go back to where mark was called.
printLines(r);
}
}
Try to make sure you don't read more bytes than the read ahead limit you set in .mark() before calling .reset().
P.S. - Not all streams (or readers) support .mark(), which you can check with .markSupported().
Reset() resets the line reader to the most recent mark (which is the last if you are going sequentially.) What you need to do is manually change the line by calling " reader.SetLineNumber(0); " the parameter indicates the line number that you want to go to.

Bufferedreader explanation?

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.in(Standard input stream)- gets the input from keyboard in bytes
InputStreamReader: Converts the bytes into Unicode characters/ converts the standard input into reader object to be used with BufferedReader
Finally BufferedReader: Used to read from character input stream(Input stream reader)
String c = br.ReadLine(); -- a method used to read characters from input stream and put them in the string in one go not byte by byte.
Is everything above right ? Please correct if anything wrong !
Nearly there, but this:
String c = br.readLine(); -- a method used to read characters from input stream and put them in the string in one go not byte by byte.
It reads characters from the input reader (BufferedReader doesn't know about streams) and returns a whole line in one go, not character by character. Think of it in layers, and "above" the InputStreamReader layer, the concept of "bytes" doesn't exist any more.
Also, note that you can read blocks of characters with a Reader without reading a line: read(char[], int, int) - the point of readLine() is that it will do the line ending detection for you.
(As noted in comments, it's also readLine, not ReadLine :)
What is the purpose of BufferedReader, explanation?
Bufferedreader is a java class, the following is the hierarchy of this class.
java.lang.Object ==> java.io.Reader ==> java.io.BufferedReader
Also, BufferedReader provides an efficient way to read content. Very Simple..
Let's have a look at the following example to understand.
import java.io.BufferedReader;
import java.io.FileReader;
public class Main {
public static void main(String[] args) {
BufferedReader contentReader = null;
int total = 0; // variable total hold the number that we will add
//Create instance of class BufferedReader
//FileReader is built in class that takes care of the details of reading content from a file
//BufferedReader is something that adds some buffering on top of that to make reading fom a file more efficient.
try{
contentReader = new BufferedReader(new FileReader("c:\\Numbers.txt"));
String line = null;
while((line = contentReader.readLine()) != null)
total += Integer.valueOf(line);
System.out.println("Total: " + total);
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
finally{
try{
if(contentReader != null)
contentReader.close();
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}
}

Reading in from text file character by character

In Java, is there a way of reading a file (text file) in a way that it would only read one character at a time, rather than String by String. This is for the purpose of an extremely basic lexical analyzer, so you can understand why I'd want such a method. Thank you.
Here's a sample code for reading / writing one character at a time
public class CopyCharacters {
public static void main(String[] args) throws IOException {
FileReader inputStream = null;
FileWriter outputStream = null;
try {
inputStream = new FileReader("xanadu.txt");
outputStream = new FileWriter("characteroutput.txt");
int c;
while ((c = inputStream.read()) != -1) {
outputStream.write(c);
}
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}
Note, this answer was updated to copy the sample code from the Ref link, but I see this is essentially the same answer given below.
ref:
http://download.oracle.com/javase/tutorial/essential/io/charstreams.html
You can use the read method from the InputStreamReader class which reads one character from the stream and returns -1 when it reaches the end of the stream
public static void processFile(File file) throws IOException {
try (InputStream in = new FileInputStream(file);
Reader reader = new InputStreamReader(in)) {
int c;
while ((c = reader.read()) != -1) {
processChar((char) c); // this method will do whatever you want
}
}
}
You can read the whole file (if it is not much big) in the memory as string, and iterate on the string character by character
There are several possible solutions. Generally you can use any Reader from java.io package for reading characters, e.g.:
// Read from file
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
// Read from sting
BufferedReader reader = new BufferedReader(new StringReader("Some text"));

Categories