I am running a client and servlet under jetty locally. When I read the message in the client, I do:
in = new Scanner(conn.getInputStream());
StringBuffer messageBuffer = new StringBuffer();
while (in.hasNext()) {
messageBuffer.append(in.next()).append(" ");
}
and I expect that when there is no data coming from the servlet, it should freeze at
while (in.hasNext())
instead, I just end up with empty messageBuffer, and i have to deal with it and call the method again and again until I get a message. Why is this happening? How can I make it stop at the while statement and wait until there is data coming in?
Here is how the url connection is started(once, in client constructor):
try {
url = new URL("http://localhost:8182/stream");
conn = (HttpURLConnection) url.openConnection();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException ioE) {
ioE.printStackTrace();
}
from the Scanner doc:
The next() and hasNext() methods and their primitive-type companion
methods (such as nextInt() and hasNextInt()) first skip any input that
matches the delimiter pattern, and then attempt to return the next
token. Both hasNext and next methods may block waiting for further
input. Whether a hasNext method blocks has no connection to whether or
not its associated next method will block.
it says that it might block, but it is not part of the api, it depends on the underline implementation according to what you scan.
anyway, you need to implement the wait yourself by something like:
while (!in.hasNext() && !stop){
sleep();
}
The javadoc states that Scanner.hasNext() and Scanner.next() may block. It really depends on the underlying InputStream. I personally wouldn't ever use a Scanner to read from a socket if that's what that is.
A more sane approach is probably to use an an InputStreamReader wrapped by a BufferedReader. Also worth mentioning is that you should be using StringBuilder rather than StringBuffer unless you need thread safety.
BufferedReader br =
new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String input = null;
while ((input = br.readLine()) != null)
{
sb.append(input).append(" ");
}
Note this is using readLine() which may or may not suit your needs depending on what you're receiving. It also assumes the other end of the connection is going to close when it's done sending. You may want to use one of the read() methods instead and parse accordingly.
Edit to add from comments below: This is literally how blocking reads work in Java. Here's a complete example:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class App
{
public static void main( String[] args ) throws MalformedURLException, IOException
{
URL url = new URL("http://www.google.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
BufferedReader br =
new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder sb = new StringBuilder();
String input = null;
while ((input = br.readLine()) != null)
{
sb.append(input).append(" ");
}
System.out.println(sb.toString());
}
}
Output (cut off for brevity here, but it's the entire page):
<!doctype html><html itemscope="itemscope" itemtype="http://schema.org/WebPage"><head> ...
In my experience, I have always tried to avoid blocking and therefore have avoided using Scanner methods for hasNext().
Instead, I have used the InputStream. InputStream, which you have used in the code:
conn.getInputStream();
You can then use the InputStream method available() to see if any information has passed through.
So for your code, I would recommend:
InputStream inStream = conn.getInputStream();
in = new Scanner(inStream);
StringBuffer messageBuffer = new StringBuffer();
while (in.available() <= 0)
{
try{
Thread.sleep(100);
}
catch(InterruptedException e){}
}
messageBuffer.append(in.next()).append(" ");
Edited :
try using for loop instead of while loop, where the range will be from 0 to (length -1). you will have to find length using while(in.hasNextLine()) and put length counter inside it .Dont forget to close the scanner after you are done with filling the messageBuffer (using .close()). just try it out. It should work.
Related
I am writing a method but see this error: may fail to close stream.
According to some solutions on different posts, I have added try and catch within the finally block. I also added IOUtils.closeQuietly(fullObject, (Log) LOGGER). But it still doesn't work. Anyone can help take a look? Thanks!
S3Object fullObject = null;
StringBuffer buffer = new StringBuffer();
try {
S3Object s3Response = s3Client.getObject(s3BucketName, s3Key);
BufferedReader reader = new BufferedReader(new InputStreamReader(s3Response.getObjectContent()));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
} finally {
if (fullObject != null) {
try {
fullObject.close();
} catch (IOException ex) {
throw new RuntimeException(ex);
}
IOUtils.closeQuietly(fullObject, (Log) LOGGER);
}
}
return buffer.toString();
}
You should be using Java 7+ try with resources. It will take care of closing the resources you declare in the list. Any exceptions that may be thrown in the process of closing will be dealt with appropriately. (They are either allowed to propagate, or they are "suppressed" if an exception was already propagating.)
Your code using try with resources would look like this. It is half the length of the original version AND it won't have any resource leaks. You "win" both ways.
try (S3Object s3Response = s3Client.getObject(s3BucketName, s3Key);
BufferedReader reader = new BufferedReader(
new InputStreamReader(s3Response.getObjectContent()));
)
{
StringBuffer buffer = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
return buffer.toString();
}
Notice that I have gotten rid of fullObject which your code wasn't using.
There are actually two managed resources in the above: the s3Response and the reader. It might not be strictly necessary to close both, but (IMO) closing them anyway is the correct thing to do ... from the perspective of readability, if nothing else.
(It may also be possible to do the "read content as a string" more simply and/or more efficiently, but that is outside of the scope of this question.)
InputStreamReader implements AutoCloseable. This means that the intended use is try-with-resources:
try (InputStreamReader reader = new InputStreamReader(s3Response.getObjectContent()) {
...
}
This should always close the stream irrespective of how the block exits (i.e. through normal completion, catch or finally clauses).
The same is true for S3Object and BufferedReader. They can all be declared as resources within the same try block.
See https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html for more details.
I've got the following piece of code:
public ArrayList<Crime> loadCrimes() throws IOException, JSONException {
ArrayList<Crime> crimes = new ArrayList<Crime>();
BufferedReader reader = null;
try {
// Open and read the file into a StringBuilder
InputStream in = mContext.openFileInput(mFilename);
//what if an exception gets thrown in the line below?
reader = new BufferedReader(new InputStreamReader(in));
StringBuilder jsonString = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
// Line breaks are omitted and irrelevant
jsonString.append(line);
}
// Parse the JSON using JSONTokener
JSONArray array = (JSONArray) new JSONTokener(jsonString.toString()).nextValue();
// Build the array of crimes from JSONObjects
for (int i = 0; i < array.length(); i++) {
crimes.add(new Crime(array.getJSONObject(i)));
}
} catch (FileNotFoundException e) {
// Ignore this one; it happens when starting fresh
} finally {
if (reader != null)
reader.close();
}
return crimes;
}
First, I wondered why we call .close() just on the BufferedReader object and not on the InputStream and InputStreamReader objects. I checked the official Oracle documentation and skimmed through a couple of questions in stackoverflow and according to what I've read BufferedReader.close() takes care of releasing the resources acquired by InputStreamReader and InputStream, so I don't have to call .close() on them.
Is this correct?
Secondly, I thought what would happen if an exception got thrown after creating the InputStream object and before creating the BufferedReader object. That is, either the InputStreamReader(InputStream in) constructor or BufferedReader(Reader in) constructor throws an exception. In that case we have acquired a file resource with InputStream but the BufferedReader object is still null, so in the finally block, the .close() method will not be invoked and the InputStream will not release the resources it has acquired.
Then I read the Oracle documentation, and neither of those two constructors throw an exception according to it. So it's not possible for an exception to occur between those two lines, right?
My final question is "Does this piece of code make sure it releases all resources it acquires?"
First, I wondered why we call .close() just on the BufferedReader object and not on the InputStream and InputStreamReader objects. I checked the official Oracle documentation and skimmed through a couple of questions in stackoverflow and according to what I've read BufferedReader.close() takes care of releasing the resources acquired by InputStreamReader and InputStream, so I don't have to call .close() on them.
Is this correct?
Yes, it is.
My final question is "Does this piece of code make sure it releases all resources it acquires?"
Most probably, yes. Even if some odd exceptions occur when creating the InputStreamReader or the BufferedReader, after exiting the block where they're defined, before GC collects them, they will be automatically closed as well. Of course, it's usually not a good idea to count on the GC to cleanup for you so if you want to be 100% sure, you might want to do it yourself in the finally block.
Another easier way is to use a FileReader which will simplify the code by only using two objects:
BufferedReader reader = new BufferedReader(new FileReader(fileName));
(I am assuming you want to read from a file).
If I have something like this in my code:
String line = r.readLine(); //Where r is a bufferedReader
How can I avoid a crash if the next line is the end of the file? (i.e. null)
I need to read the next line because there may be something there that I need to deal with but if there isn't the code just crashes.
If there is something there then all is OK, but I can't be guaranteed that there will be something there.
So if I do something like: (pseudo code):
if (r.readLine is null)
//End code
else {check line again and excecute code depending on what the next line is}
The issue I have with something like this is, that when I check the line against null, it already moves onto the next line, so how can I check it again?
I've not worked out a way to do this - any suggestions would be a great help.
Am... You can simply use such a construction:
String line;
while ((line = r.readLine()) != null) {
// do your stuff...
}
If you want loop through all lines use that:
while((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
You can use the following to check for the end of file.
public bool isEOF(BufferedReader br)
{
boolean result;
try
{
result = br.ready();
}
catch (IOException e)
{
System.err.println(e);
}
return result;
}
In your case you can read the next line because there may be something there.If there isn't anything, your code won't crash.
String line = r.readLine();
while(line!=null){
System.out.println(line);
line = r.readLine();
}
A question in the first place, why don't you use "Functional Programming Approach"? Anyways, A new method lines() has been added since Java 1.8, it lets BufferedReader returns content as Stream. It gets all the lines from the file as a stream, then you can sort the string based on your logic and then collect the same in a list/set and write to the output file. If you use the same approach, there is no need to get worried about NullPointerException. Below is the code snippet for the same:-
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Collectors;
public class LineOperation {
public static void main(String[] args) throws IOException {
Files.newBufferedReader(Paths.get("C://xyz.txt")).
lines().
collect(Collectors.toSet()). // You can also use list or any other Collection
forEach(System.out::println);
}
}
You can do it via BufferReader. I know this is not relevant to following question. But I would post it for extra fact for a newbie who would not use BufferReader but Scanner for reading file.
A part from BufferReader you could use Java Scanner class to read the file and check the last line.
Buffer Reader
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// process the line
}
}
Scanner
try {
Scanner scanner = new Scanner(new FileReader(file));
while (scanner.hasNext()) {
// Above checks whether it has or not ....
}
} catch (IOException e) {
e.printStackTrace();
}
If you use this code fragment in a multi threaded environment, go ahead with BufferReader since its synchronized.
In addition, BufferReader is faster than Scanner.
If you would like to do some check like:
if (reader.ready())
stringBuilder.append("#");
You can use ready()
public static void check() throws IOException {
InputStream in = new FileInputStream(new File(filePath));
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
if (reader.ready())
stringBuilder.append("#");
}
String returnedString = stringBuilder.toString();
System.out.println(returnedString);
}
You could purposely have it throw the error inside your loop. i.e.:
String s = "";
while (true) {
try {
s = r.readline();
}catch(NullPointerException e) {
r.close();
break;
}
//Do stuff with line
}
what everyone else has sad should also work.
I currently have the follow method:
try {
URL url = new URL("http://auth.h.gp/HAKUNA%20MATATA.txt");
Scanner s = new Scanner(url.openStream());
}
catch(IOException ex) {
BotScript.log("Something went wrong =/ Error code:");
ex.printStackTrace();
stop();
}
However, how do I check if it contains a word? I've never worked with Scanners before and I found this snippet online.
Thank you.
Okay, that looks good so far.
You can then use Scanner's next() method to get each word. You can also query hasNext() to see if there's another token available to avoid errors.
boolean foundPumbaa = false;
while (s.hasNext()) {
if (s.next().equalsIgnoreCase("pumbaa")) {
foundPumbaa = true;
System.out.println("We found Pumbaa"); // do something
break;
}
}
if (!foundPumbaa) {
System.out.println("We didn't find Pumbaa");
}
EDIT in response to comment:
Yes, you can turn the text into a String. The best way to do this is probably with a BufferedReader.
From the Java Tutorial, "Reading Directly from a URL":
The following small Java program uses openStream() to get an input
stream on the URL http://www.oracle.com/. It then opens a
BufferedReader on the input stream and reads from the BufferedReader
thereby reading from the URL. Everything read is copied to the
standard output stream:
import java.net.*;
import java.io.*;
public class URLReader {
public static void main(String[] args) throws Exception {
URL oracle = new URL("http://www.oracle.com/");
BufferedReader in = new BufferedReader(
new InputStreamReader(oracle.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}
}
In a real program, instead of main throws Exception, you'd have that in a try-catch block and catch an IOException and some various URLExceptions. But this should get you started.
I am trying to read text from a web document using a BufferedReader over an InputStreamReader on an URL (to the file on some Apache server).
String result = "";
URL url = new URL("http://someserver.domain/somefile");
BufferedReader in = null;
in = new BufferedReader(new InputStreamReader(url.openStream(), "iso-8859-1"));
result += in.readLine();
Now this works just fine. But Obviously I'd like the reader not to just read one line, but as many as there are in the file.
Looking at the BufferedReader API the following code should do just that:
while (in.ready()) {
result += in.readLine();
}
I.e. read all lines while there are more lines, stop when no more lines are there. This code does not work however - the reader just never reports ready() = true!
I can even print the ready() value right before reading a line (which reads the correct string from the file) but the reader will report 'false'.
Am I doing something wrong? Why does the BufferedReader return 'false' on ready when there is actually stuff to read?
ready() != has more
ready() does not indicate that there is more data to be read. It only shows if a read will could block the thread. It is likely that it will return false before you read all data.
To find out if there is no more data check if readLine() returns null.
String line = in.readLine();
while(line != null){
...
line = in.readLine();
}
Another way you can do this that bypasses the in.ready() is something like:
while ((nextLine = in.readLine()) != null) {
result += nextLine;
}
You will just continue reading until you are done. This way you do not need to worry about the problem with in.ready().
I think the standard way to write this is to just attempt to read the line and verify that it returned sometime. Something like this:
while ((String nextLine = in.readLine()) != null) {
//System.out.println(nextLine);
result += nextLine;
}
So you just continue to go until you get null returned from the stream. See here for extra information:
http://download.oracle.com/javase/1.5.0/docs/api/java/io/BufferedReader.html#readLine()
The BufferedReader.ready() method is behaving as specified:
The Reader.ready() javadoc says the following:
[Returns] true if the next read() is guaranteed not to block for input, false otherwise. Note that returning false does not guarantee that the next read will block.
Then the BufferedReader.ready() javadoc says the following:
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.
If you put these two together, it is clear that BufferedReader.ready() can return false in situations where are characters available. In short, you shouldn't rely on ready() to test for logical end-of-file or end-of-stream.
This is what we have been using consistently for years - not sure if it is the "standard" method. I'd like to hear comments about the pros and cons of using URL.openURLStream() directly, and if that is causing the OP's problems. This code works for both HTTP and HTTPS connections.
URL getURL = new URL (servletURL.toString() + identifier+"?"+key+"="+value);
URLConnection uConn = getURL.openConnection();
BufferedReader br = new BufferedReader (new
InputStreamReader (uConn.getInputStream()));
for (String s = br.readLine() ; s != null ; s = br.readLine()) {
System.out.println ("[ServletOut] " + s);
// do stuff with s
}
br.close();
Basically the BufferedReader.ready() method can be used for checking whether the underlying stream is ready for providing data to the method caller.... else we can wait the thread for some time till it becomes ready.
But the real problem is that after we completely read the data stream, it will throw false..
so we didn't know whether the stream is fully read OR underlying stream is busy....
If you want to use in.ready(), the following worked for me well:
for (int i = 0; i < 10; i++) {
System.out.println("is InputStreamReader ready: " + in.ready());
if (!in.ready()) {
Thread.sleep(1000);
} else {
break;
}
}