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.
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.
Good evening!
I have been reading through stuff on the internet for hours now but I can't find any way to get the conent of a file from the internet into an int array.
I got a .txt file (that I download from the internet) which is loaded over a BufferedStreamInput. There is a byte array which I tried to make use of it, but didn't have much success. Inside the file are random letters such as "abcCC". Now I would need the int value of each character (such as 97,98,99,67,67). I would add them to an array and then count how often a specific value appears. My problem tho is to get those values from the stream and I don't seem to find a way to do so.
Thank you for any ideas!
The Java API already contains a method that seems very convenient for you. InputStream defines the following method.
public abstract int read() throws IOException;
Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned. This method blocks until input data is available, the end of the stream is detected, or an exception is thrown.
It should make it trivial to read integers from a file one byte at a time (assuming characters to integers is one-to-one; int is actually four bytes in size).
An example of using this method to read characters individually as int and then casting to char follows. Again, this assumes that each character is encoded as a single byte, and that there is a one-to-one from characters to ints. If you're dealing with multi-byte character encoding and/or you want to support integers greater than 255, then the problem becomes more complex.
public static void main(String[] args) {
ByteArrayInputStream in = new ByteArrayInputStream("abc".getBytes());
int value;
while ((value = in.read()) > -1) {
System.out.println((char) value);
}
}
I would use a
java.util.Scanner.
You can initialize it with many different options including
File
InputStream
Readable
Later you can process the whole input line by line or in any way you like.
please refer to the great javadoc of Scanner.
Regards,
z1pi
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');
}
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.
I use BufferedReader's readLine() method to read lines of text from a socket.
There is no obvious way to limit the length of the line read.
I am worried that the source of the data can (maliciously or by mistake) write a lot of data without any line feed character, and this will cause BufferedReader to allocate an unbounded amount of memory.
Is there a way to avoid that? Or do I have to implement a bounded version of readLine() myself?
The simplest way to do this will be to implement your own bounded line reader.
Or even simpler, reuse the code from this BoundedBufferedReader class.
Actually, coding a readLine() that works the same as the standard method is not trivial. Dealing with the 3 kinds of line terminator CORRECTLY requires some pretty careful coding. It is interesting to compare the different approaches of the above link with the Sun version and Apache Harmony version of BufferedReader.
Note: I'm not entirely convinced that either the bounded version or the Apache version is 100% correct. The bounded version assumes that the underlying stream supports mark and reset, which is certainly not always true. The Apache version appears to read-ahead one character if it sees a CR as the last character in the buffer. This would break on MacOS when reading input typed by the user. The Sun version handles this by setting a flag to cause the possible LF after the CR to be skipped on the next read... operation; i.e. no spurious read-ahead.
Another option is Apache Commons' BoundedInputStream:
InputStream bounded = new BoundedInputStream(is, MAX_BYTE_COUNT);
BufferedReader reader = new BufferedReader(new InputStreamReader(bounded));
String line = reader.readLine();
The limit for a String is 2 billion chars. If you want the limit to be smaller, you need to read the data yourself. You can read one char at a time from the buffered stream until the limit or a new line char is reached.
Perhaps the easiest solution is to take a slightly different approach. Instead of attempting to prevent a DoS by limiting one particular read, limit the entire amount of raw data read. In this way you don't need to worry about using special code for every single read and loop, so long as the memory allocated is proportionate to incoming data.
You can either meter the Reader, or probably more appropriately, the undecoded Stream or equivalent.
There are a few ways round this:
if the amount of data overall is very small, load data in from the socket into a buffer (byte array, bytebuffer, depending on what you prefer), then wrap the BufferedReader around the data in memory (via a ByteArrayInputStream etc);
just catch the OutOfMemoryError, if it occurs; catching this error is generally not reliable, but in the specific case of catching array allocation failures, it is basically safe (but does not solve the issue of any knock-on effect that one thread allocating large amounts from the heap could have on other threads running in your application, for example);
implement a wrapper InputStream that will only read so many bytes, then insert this between the socket and BufferedReader;
ditch BufferedReader and split your lines via the regular expressions framework (implement a CharSequence whose chars are pulled from the stream, and then define a regular expression that limits the length of lines); in principle, a CharSequence is supposed to be random access, but for a simple "line splitting" regex, in practice you will probably find that successive chars are always requested, so that you can "cheat" in your implementation.
In BufferedReader, instead of using String readLine(), use int read(char[] cbuf, int off, int len); you can then use boolean ready() to see if you got it all and convert in into a string using the constructor String(byte[] bytes, int offset, int length).
If you don't care about the whitespace and you just want to have a maximum number of characters per line, then the proposal Stephen suggested is really simple,
import java.io.BufferedReader;
import java.io.IOException;
public class BoundedReader extends BufferedReader {
private final int bufferSize;
private char buffer[];
BoundedReader(final BufferedReader in, final int bufferSize) {
super(in);
this.bufferSize = bufferSize;
this.buffer = new char[bufferSize];
}
#Override
public String readLine() throws IOException {
int no;
/* read up to bufferSize */
if((no = this.read(buffer, 0, bufferSize)) == -1) return null;
String input = new String(buffer, 0, no).trim();
/* skip the rest */
while(no >= bufferSize && ready()) {
if((no = read(buffer, 0, bufferSize)) == -1) break;
}
return input;
}
}
Edit: this is intended to read lines from a user terminal. It blocks until the next line, and returns a bufferSize-bounded String; any further input on the line is discarded.