I have a piece of code that uses a BufferedReader to read from a file and marks the current position of the reader so that I can reset to the last line when I need to. However I'm getting an I/O exception and I'm not positive why. This piece of code is in a bigger loop that also utilizes the read method which is why I'm resetting when I encounter "From:".
while((line=reader.readLine())!=null && line.indexOf("From:")!=0) {
emailMsg.append(line).append("\n");
reader.mark(0);
}
reader.reset(); //io exception: mark invalid
emailMsg.append(".\n");
The argument passed to mark() is the readAheadLimit. From the documentation:
readAheadLimit - Limit on the number of characters that may be read while still preserving the mark. An attempt to reset the stream after reading characters up to this limit or beyond may fail. A limit value larger than the size of the input buffer will cause a new buffer to be allocated whose size is no smaller than limit. Therefore large values should be used with care.
Since you have specified 0, and the next readLine() call ends up reading something from the stream, the subsequent reset has a possibility of failing since you are over the limit.
When you tell the stream to "mark" a location, you specify a read-ahead limit, which basically tells the stream to "remember" that many characters. As long as you don't read past the limit, you can call reset() how many ever times you want and it will reset it back to the beginning of that "remembered" set of characters. Once you read past that limit however, the mark is invalid and so subsequent calls to reset() will fail. In your case, you have specified a read-ahead limit of 0, which means any read past the current point will invalidate the mark, which is what you are seeing.
To get around this, specify a non-zero read-ahead limit.
To me it looks, like the line you read from reader does not contain "From:" sequence, so execution does not enter while-loop, so the mark is not set, and when execution continues right after while-loop body, reset throws an exception, because the mark was not set, as per reset() documentation.
You rather need this:
boolean marked = false;
while ((line = reader.readLine()) != null) {
if (line.indexOf("From:") != 0) {
continue;
}
emailMsg.append(line).append('\n');
reader.mark(0);
marked = true;
}
if (marked) {
reader.reset();
emailMsg.append('\n');
}
Related
Before anything, allow me to show you my client code:
String command;
socket.setSoTimeout(5000);
while(true) {
try {
final byte[] targetArray = new byte[is.available()];
final int x = is.read(targetArray);
if (x == -1) {
System.out.println("end");
break;
}
if (x == 0) continue;
command = new String(targetArray);
handleCommand(command).start();
}catch (Exception e){
e.printStackTrace();
}
}
once connected to the actual socket, the client sends out some authentication data, but doesn't recieve any data, now, it waits to recieve data from the server, and when it does, it processes it fine etc, except, when I stop the server (literally shutting down the program), nothing happens, when in reality, im expecting it to send EOF (-1). Instead it just spams out 0 consistently.
According to available method's documentation (emphasis mine):
Returns an estimate of the number of bytes that can be read ...
and
It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream ...
So according to the minimal code you posted, you shouldn't use available to allocate the buffer, because it may always return 0 which in turn makes the read operation always return 0. But according to your question you only see this behaviour when the sending program is closed which should mean that:
The available method correctly returns the buffered number of bytes in the stream, so this is why you receive the data. Even if you consume received data faster than the sending end sends (so some zeros may show up in available) you just continue and never handle that case, which makes some other loop in the future to capture the (eventually) received non-zero length data.
Once the sending end is closed, there will be a point after which it will always return 0 since it has no data. So you allocate zero length buffer, and the read method first checks that your buffer is zero length, rather than EOF.
So make sure the allocated buffer is of size at least 1.
Also, according to the Socket#getInputStream method's documentation:
If there are no bytes buffered on the socket, and the socket has not been closed using close, then available will return 0.
public void createNewUser(String name, String passwort) {
try {
br = new BufferedReader(new FileReader("Data.txt"));
} catch (FileNotFoundException brCreateError) {
brCreateError.printStackTrace();
}
try {
br.mark(1);
System.out.println(br.readLine());
try {
if(br.readLine()==null) {
noUser=true;
}else {
noUser=false;
}
} catch (IOException e) {
e.printStackTrace();
}
br.reset();
} catch (IOException brMarkError) {
brMarkError.printStackTrace();
} ...
Why is the markedChar value changing to -2 after passing the if-statement?
Thx for every answer Nico.
public void mark(int readAheadLimit)
throws IOException
Marks the present position in the stream. Subsequent calls to reset()
will attempt to reposition the stream to this point.
...
Parameters:
readAheadLimit- Limit on the number of characters that may be read while still preserving the mark. An attempt to reset the stream
after reading characters up to this limit or beyond may fail. A limit
value larger than the size of the input buffer will cause a new buffer
to be allocated whose size is no smaller than limit. Therefore large
values should be used with care.
You set the readAheadLimit to 1 character then read an entire line. This invalidated the mark.
I had the same problem with that damn exception: Mark Invalid.
I came to this forum and I did not find something that would work so I had to figure out for myself what happens.
The BufferedReader creates a buffer (who would say it) from the moment I call the BufferedReader :: mark (int readAheadLimit) function, the size of the buffer IN CHARACTERS (NOT LINES) is given by readAheadLimit.
Once this limit is exceeded, it is not possible to go back with BufferedReader :: reset (), at the time of the mark because although the first data of the buffer could be recovered the later ones (those after the maximum of the buffer size and before the position current file) it would not be possible to retrieve them.
To avoid errors, the mark is invalidated by setting it to -2, and when the reset is called, the exception is produced: Mark Invalid. The issue is that it is NOT POSSIBLE with BufferedReader, to go back the pointer to read the file, it is simulated by storing the data in memory (the buffer).
So if you run into an Invalid Mark exception, you should make the buffer larger when calling the mark (int) method.
For this, we need to understand how the BufferedReader works...
BufferReader will read 8192 characters at one shot and store it in a character buffer - cb (default value can be changed).
readLine() - will try to fetch the data from the character buffer, if it needs more characters than what is available, it will do a fetch again and fill the next 8192 characters...
mark() - is used to make the current line, so that using reset() method we can go back to the previously marked line.
mark() method takes a parameter - readAheadLimit, which should be the maximum number of characters in that line.
As given in the Java DOCS - having a limit less than the line size may fail.
https://docs.oracle.com/javase/7/docs/api/java/io/BufferedReader.html#mark(int)
If we try to fill the character array again after the character buffer
array is exhausted and the number of pending characters is more than
the marked limit (readAheadLimit). It will mark the markedChar as
INVALIDATED. The next call to reset will lead to IOException - Mark
invalid
CONCLUSION:
Make sure that the readAheadLimit is the maximum number of characters that can be present in a line.
If the line is already filled in the character buffer, you will not get any error since the check is done while trying to fill the character buffer again.
That is the significance of may fail in Java Docs.
Here is my question: normal while loop looks like this -
while(condition){statements}
and statements execute until condition becomes false and the loop is over. I'm interested in logic of this kind of statement:
while((a=b.readLine) != null) { ... }
It's used in client - server communication in my case. The condition is sometimes true, sometimes isn't, but loop looks like it's testing the condition forever and when true, statements in {} execute. It looks to me that loop waits for the condition to be true and then runs statements. Is it somehow linked to the way BufferedReader and InputStreamReader work or what? Also, it seems this loop is never over, it just waits for a condition to be true and then runs statements, and then again waits for a condition to be true, etc. I would be thankful for any clarification.
while((a = b.readLine()) != null){ ... }
At each iteration, the condition inside the parentheses is evaluated.
Evaluating this expression consists in calling b.readLine(), affecting the returned value to a, and comparing a with null.
Calling readLine(), as documented, consists in blocking until the next line is read. If there is no next line, readLine() returns null.
So, in short, this while loop reads every line from the reader, does something with the line (inside the while block) and stops when the end of the stream is reached.
The following code snippet
String a;
while((a = b.readLine()) != null) { // a = b.readLine() -> a -> a != null
...
}
is equivalent to
String a = b.readLine();
while(a != null) {
...
a = b.readLine();
}
but the first way is more simple, readable, and Java allows using assignment operators here because they return the value of a renewed variable.
This idiom
while ( (a = b.readLine()) != null) { /* body */ }
is a normal while loop, but the condition happens to contain an embedded assignment operator, which yields the result of the assignment, which is compared to null.
Whether b is reading from a socket, a file, or any other input stream, presumably b is something like a BufferedReader with its readLine() method. This method will only return null when the end of the stream is reached. It will block if the end of the stream hasn't been reached yet, but not further input consisting of a newline character has been read off the stream yet.
When such a line is available, a is not null and the body of the loop executes. The result of readLine is assigned to a for convenient processing withing the body of the loop.
When the end of the stream is reached, a is null and the while loop ends.
This idiom allows for easy processing of an entire stream of data, whether it is from an entire file, from an entire socket connection, or otherwise generally reading from an entire input stream of data. It looks more complicated than a simpler while loop, but it's just a standard while loop with a more complicated condition.
Because most IO streams don't read all data at once but bits-by-bits, putting the read() or readLine() assignment as part of the WHILE condition ensures that the WHILE block continues to loop as the input stream is read bits-by-bits until there's nothing to left to read (that is, all data have been read).
I am learning how to use an InputStream. I was trying to use mark for BufferedInputStream, but when I try to reset I have these exceptions:
java.io.IOException: Resetting to invalid mark
I think this means that my mark read limit is set wrong. I actually don't know how to set the read limit in mark(). I tried like this:
is = new BufferedInputStream(is);
is.mark(is.available());
This is also wrong.
is.mark(16);
This also throws the same exception.
How do I know what read limit I am supposed to set? Since I will be reading different file sizes from the input stream.
mark is sometimes useful if you need to inspect a few bytes beyond what you've read to decide what to do next, then you reset back to the mark and call the routine that expects the file pointer to be at the beginning of that logical part of the input. I don't think it is really intended for much else.
If you look at the javadoc for BufferedInputStream it says
The mark operation remembers a point in the input stream and the reset operation causes all the bytes read since the most recent mark operation to be reread before new bytes are taken from the contained input stream.
The key thing to remember here is once you mark a spot in the stream, if you keep reading beyond the marked length, the mark will no longer be valid, and the call to reset will fail. So mark is good for specific situations and not much use in other cases.
This will read 5 times from the same BufferedInputStream.
for (int i=0; i<5; i++) {
inputStream.mark(inputStream.available()+1);
// Read from input stream
Thumbnails.of(inputStream).forceSize(160, 160).toOutputStream(out);
inputStream.reset();
}
The value you pass to mark() is the amount backwards that you will need to reset. if you need to reset to the beginning of the stream, you will need a buffer as big as the entire stream. this is probably not a great design as it will not scale well to large streams. if you need to read the stream twice and you don't know the source of the data (e.g. if it's a file, you could just re-open it), then you should probably copy it to a temp file so you can re-read it at will.
Is there a way to flush the input stream in Java, perhaps prior to closing it? In relation to
iteratively invoking the statements below, while reading several files on disk
InputStream fileStream = item.openStream();
fileStream.close;
InputStream cannot be flushed. Why do you want to do this?
OutputStream can be flushed as it implements the interface Flushable. Flushing makes IMHO only sense in scenarios where data is written (to force a write of buffered data). Please see the documentation of Flushable for all implementing classes.
This is an old question but appears to be the only one of its kind, and I think there is a valid use case for "flushing" an input stream.
In Java, if you are using a BufferedReader or BufferedInputStream (which I believe is a common case), "flushing" the stream can be considered to be equivalent to discarding all data currently in the buffer -- i.e., flushing the buffer.
For an example of when this might be useful, consider implementing a REPL for a programming language such as Python or similar.
In this case you might use a BufferedReader on System.in. The user enters a (possibly large) expression and hits enter. At this point, the expression (or some part of it) is stored in the buffer of your Reader.
Now, if a syntax error occurs somewhere within the expression, it will be caught and displayed to the user. However, the remainder of the expression still resides in the input buffer.
When the REPL loop continues, it will begin reading just beyond the point where the syntax error occurred, in the middle of some erroneous expression. This is likely not desirable. Rather, it would be better to simply discard the remainder of the buffer and continue with a "fresh start."
In this sense, we can use the BufferedReader API method ready() to discard any remaining buffered characters. The documentation reads:
"Tells whether this stream is ready to be read. A buffered character stream is ready if the buffer is not empty, or if the underlying character stream is ready."
Then we can define a method to "flush" a BufferedReader as:
void flush(BufferedReader input) throws IOException
{
while (input.ready())
input.read();
}
which simply discards all remaining data until the buffer is empty. We then call flush() after handling a syntax error (by displaying to the user). When the REPL loop resumes you have an empty buffer and thus do not get a pile of meaningless errors caused by the "junk" left in the buffer.