I have something akin to the following:
public class X extends Thread{
BufferedInputStream in = (BufferedInputStream) System.in;
public void run() {
while (true) {
try {
while (in.available() > 0) {
// interesting stuff here
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
... which largely works, however sometimes I'll start seeing the following in stderr (seems to repeat incessantly once it happens - I'm guessing the application eventually crashes once this starts occurring):
java.io.IOException: Illegal seek
at java.io.FileInputStream.available(Native Method)
at java.io.BufferedInputStream.available(BufferedInputStream.java:381)
at compactable.sqlpp.X.run(X.java:40)
... and I have no clue what causes this. Honestly stumped. Any ideas from the masses on how this could happen ?
Any / all useful suggestions gratefully received :-)
If the stream has been closed you can get an IOException calling available.
Also, available() does not tell you how much is left to read of the stream or if the stream is empty, it only tells how much you can read without blocking (basically waiting for more to be put into the stream). What you want is to read until your read returns -1.
int c;
while ( (c = in.read()) != -1 ) {
// do stuff
}
or
int readLength;
byte[] buffer = new byte[1024];
while ( (length = in.read(buffer) != -1) {
// do stuff with buffer, it now has bytes in buffer[0] to buffer[readLength-1]
}
Related
I am trying to make a file transfer Bluetooth app work using these sources:
http://developer.android.com/guide/topics/connectivity/bluetooth.html
https://android.googlesource.com/platform/development/+/25b6aed7b2e01ce7bdc0dfa1a79eaf009ad178fe/samples/BluetoothChat/
When I attempt to get the InputStream bytes using InputStream.read() method this way:
public class ConnectedThread extends Thread {
...(some code here)
public void run(){
byte[] buffer = new byte[1024];
int bytes = -1;
//Keep listening to the InputStream while connected
while (true){
try {
bytes = this.mmInStream.read(buffer);
//* this part is not reached
if (bytes==-1){
Log.d("NoData:","-1");
}
}
catch(Exception e){
Log.d("inStream exception:",e.getMessage());
break;
}
}
}
...(some code here)
}
The next part of the code ("if" part in this case) is never reached, nor a Log.D debug output or whatever else I put in following. I just get this message from LogCat:
BluetoothSocket read in: android.net.LocalStocketImpl$SocketInputStream#f7e
b08 len: 1024
To transfer the data from the Client to the Server I am doing this:
public class MainActivity extends Activity {
...(some code here)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
clientConnect();
//serverConnect();
}
...(some code here)
public void clientConnect(){
Set<BluetoothDevice> devices;
devices = bConfig.getPairedDevices();
if (devices == null){
return;
}
if (devices.size() > 0) {
BluetoothDevice device = devices.iterator().next();
ConnectThread connectTransmit = new ConnectThread(device,bConfig.getBluetoothAdapter(),BluetoothConfig.mUUID);
connectTransmit.start();
Toast.makeText(this, "connected", Toast.LENGTH_SHORT).show();
socket = connectTransmit.mmSocket;
ConnectedThread connectedThread = new ConnectedThread(socket);
//write file bytes to the connected thread, so the thread can receive its own input written bytes later
File file_to_transfer = new File(Environment.getExternalStorageDirectory() + "/txtTransfer.txt");
//get bytes from our File
int size = (int) file_to_transfer.length();
byte[] bytes = new byte[size];
try {
//14b are read succesfully, the whole text file
BufferedInputStream buf = new BufferedInputStream(new FileInputStream(file_to_transfer));
buf.read(bytes,0,bytes.length);
buf.close();
}catch (FileNotFoundException e){
Log.d("FileNotFoundException:",e.getMessage());
}catch (IOException e){
Log.d("IOException:",e.getMessage());
}
//send the data to the server
connectedThread.start();
connectedThread.write(bytes);
//connectedThread.cancel();
}
}
...(some code here)
}
The AcceptThread (Server part of the implementation) works, because when I run the client part to connect and then transfer the data, while debuging in the device the LogCat on the Server part activates and reaches the run method of the thread, where I call the ConnectedThread implementation but then after it "apparently" reads the bytes but it gets stuck on LogCat with no error.
Please let me know what can I do to finish reading the bytes to move to the next part of the flow.
Thank you
You're blocked waiting for more input.
The part labelled ... (some code here) should be inside the read loop, after the test for end of stream. NB If read() returns -1 it doesn't mean 'no data', it means end of stream, and you should close the socket and break out of the read loop. Otherwise you should then go on to process the data you've just read. At present you just read and ignore all input until end of stream, which is pointless. At best you can only process the last partial buffer, and you won't know how long it was.
In my opinion You should verify if something is in buffer before reading.
reading from stream is blocking operation so aplication will hang until somehing data appear.
How can I check if an InputStream is empty without reading from it?
In your client code you should probably keep the connectedThread object alive a while longer. Might be that once the if clause closes and it goes out of scope (not quite sure what happens with GC and all) the write just doesn't happen and your connection is not closed but not used either.
Calling flush() on the mmOutStream inside the connectedThread after the write might help also.
Like #EJP suggested, you should put something inside your read loop.
Edit: For the sake of debugging you could add this.wait(1000); immediately after your write in the client code.
Try changing your run method to this:
public void run(){
byte[] buffer = new byte[1024];
int bytesRead = 0;
final int shortSleepTime = 1000;
final int longSleepTime = 5000;
int emptyReadCounter = 0;
int sleepCounter = 0;
int currentSleepTime = shortSleepTime;
//Keep listening to the InputStream while connected
while (bytesRead >= 0){
try {
// if available() returns 0, there is nothing to read yet
if (this.mmInStream.available() != 0){
bytesRead = this.mmInStream.read(buffer);
// Check if we need to reset the sleep counters
if (emptyReadCounter != 0){
emptyReadCounter = 0;
sleepCounter = 0;
currentSleepTime = shortSleepTime;
// We can also do anything else dependent on just waking up
// from a sleep cycle in this block
}
// Do something with my now full buffer
// Remember not to process more than
// 'bytesRead' bytes from my buffer because the
// rest could be filled with crap left over from
// the last iteration
} else {
// Three consecutive empty reads means sleep
if (emptyReadCounter++ >= 3){
if (currentSleepTime != longSleepTime && sleepCounter++ >= 3){
currentSleepTime = longSleepTime;
}
Thread.sleep(currentSleepTime);
}
}
}
catch(Exception e){
Log.d("inStream exception:",e.getMessage());
break;
}
}
}
I currently have a working parser. It parses a file once(not what I want it to do) and then outputs parsed data into a file. I need it to keep parsing and appending to the same output file until the end of the input file. Looks something like this.
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Everything is done except the while loop. It only parses once when I need it to keep parsing. I'm looking for a while loop function to reach eof.
I'm also using a DataInputStream. Is there some sort of DataInputStream.hasNext function?
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
i.e. dis.read();
.
//Need a while !eof while loop
try {
// my code parsing the data and appending to eof of output. (works)
}
catch (EOFException eof){
}
Warning: This answer is incorrect. See the comments for explanation.
Instead of looping until an EOFException is thrown, you could take a much cleaner approach, and use available().
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
while (dis.available() > 0) {
// read and use data
}
Alternatively, if you choose to take the EOF approach, you would want to set a boolean upon the exception being caught, and use that boolean in your loop, but I do not recommend it:
DataInputStream dis = new DataInputStream(new FileInputStream(inFile));
boolean eof = false;
while (!eof) {
try {
// read and use data
} catch (EOFException e) {
eof = true;
}
}
DataInputStream has a lot of readXXX() methods that do throw EOFException but the method that you're using DataInputStream.read() does not throw EOFException.
To correctly identify the EOF while using read() implement your while loop as follows
int read = 0;
byte[] b = new byte[1024];
while ((read = dis.read(b)) != -1) { // returns numOfBytesRead or -1 at EOF
// parse, or write to output stream as
dos.write(b, 0, read); // (byte[], offset, numOfBytesToWrite)
}
If you are using FileInputStream, here's an EOF method for a class that has a FileInputStream member called fis.
public boolean isEOF()
{
try { return fis.getChannel().position() >= fis.getChannel().size()-1; }
catch (IOException e) { return true; }
}
I am trying to write a thread which will do following stuffs:
1. read from inputstream;
2. some other routine;
3. if socket is closed, throw an exception.
The BlueTooth Socket and inputStream from the socket has been set up before this. The code is as following:
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while (true) {
try {
//if(mInputStream.available() > 0){ //-------- Line 1
bytes = mInputStream.read(buffer);
//} //-------- Line 2
//---------------------//
// some other routines //
//---------------------//
} catch (IOException e) {
connectionLost();
break;
}
}
}
The problem is that the above code will hang at mInputStream.read() because of the blocking. However, if I uncomment Line 1 and Line 2, the mInputStream.available() function will not throw exception even if BlueToothSocket is closed. Is there any method either to unblock read function, or to throw an exception when available() is used and BlueTooth Socket is closed? Appreciate it!
This is what I use:
private boolean receivedInTimelyManner(InputStream mInStream,
int bytesToReceive, long timeoutMillis) throws IOException,
InterruptedException {
long time = 0;
while (mInStream.available() < bytesToReceive && time < timeoutMillis) {
time+=5;
Thread.sleep(5);
}
if (time == timeoutMillis) {
return false;
}
return true;
}
Surround your read block with something like:
if receivedInTimelyManner(instream,bytes,timeout){
read()
}
Ok, seems there is not an easy way to do unblocked read() and available() throwing is not working. The most convenient way to work this out is to create another thread to do the other routines. While leave this thread alone particularly for reading inputstream and checking inputstream status(exception thrown).
This is my code, I'm using rxtx.
public void Send(byte[] bytDatos) throws IOException {
this.out.write(bytDatos);
}
public byte[] Read() throws IOException {
byte[] buffer = new byte[1024];
int len = 20;
while(in.available()!=0){
in.read(buffer);
}
System.out.print(new String(buffer, 0, len) + "\n");
return buffer;
}
the rest of code is just the same as this, i just changed 2 things.
InputStream in = serialPort.getInputStream();
OutputStream out = serialPort.getOutputStream();
They are global variables now and...
(new Thread(new SerialReader(in))).start();
(new Thread(new SerialWriter(out))).start();
not exist now...
I'm sending this (each second)
Send(("123456789").getBytes());
And this is what i got:
123456789123
456789
123456789
1234567891
23456789
can anybody help me?
EDIT
Later, i got the better way to solve it. Thanks, this was the Read Code
public byte[] Read(int intEspera) throws IOException {
try {
Thread.sleep(intEspera);
} catch (InterruptedException ex) {
Logger.getLogger(COM_ClComunica.class.getName()).log(Level.SEVERE, null, ex);
}//*/
byte[] buffer = new byte[528];
int len = 0;
while (in.available() > 0) {
len = in.available();
in.read(buffer,0,528);
}
return buffer;
}
It was imposible for me to erase that sleep but it is not a problem so, thanks veer
You should indeed note that InputStream.available is defined as follows...
Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.
As you can see, this is not what you expected. Instead, you want to check for end-of-stream, which is indicated by InputStream.read() returning -1.
In addition, since you don't remember how much data you have already read in prior iterations of your read loop, you are potentially overwriting prior data in your buffer, which is again not something you likely intended.
What you appear to want is something as follows:
private static final int MESSAGE_SIZE = 20;
public byte[] read() throws IOException {
final byte[] buffer = new byte[MESSAGE_SIZE];
int total = 0;
int read = 0;
while (total < MESSAGE_SIZE
&& (read = in.read(buffer, total, MESSAGE_SIZE - total)) >= 0) {
total += read;
}
return buffer;
}
This should force it to read up to 20 bytes, less in the case of reaching the end of the stream.
Special thanks to EJP for reminding me to maintain the quality of my posts and make sure they're correct.
Get rid of the available() test. All it is doing is telling you whether there is data ready to be read without blocking. That isn't the same thing as telling you where an entire message ends. There are few correct uses for available(), and this isn't one of them.
And advance the buffer pointer when you read. You need to keep track of how many bytes you have read so far, and use that as the 2nd parameter to read(), with buffer.length as the third parameter.
First off let me apologize to the SO community for coming to you with something that ought to be so trivial. But I've been at this all day and I'm at the end of my rope.
There is a section of my program that needs pull text from an input stream and an error stream from a process that is launched using Runtime.getrunTime().exec() and pass it through to standard input and output in an orderly manner. I have a function that near as I can tell should work. But it seems to be getting caught in a catch-22 where it's waiting for the stream to report ready - but the stream has finished and is not reporting. I'm baffled. I can't think of another way to do this that fits my constraints and I'm rather skeptical that such a catch-22 can exist.
Here is my code:
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
int c = -1;
BufferedReader inReader = new BufferedReader(
new InputStreamReader(in, "US-ASCII"));
BufferedReader errReader = new BufferedReader(
new InputStreamReader(err, "US-ASCII"));
boolean inFinished = false, errFinished = false;
try {
System.out.println("Begin stream read loop...");
while (!inFinished && !errFinished) {
if (!inFinished) {
while (inReader.ready()) {
if ((c = inReader.read()) == -1) {
inFinished = true;
}
else {
System.out.print((char) c);
}
}
}
if (!errFinished) {
while (errReader.ready()) {
if ((c = errReader.read()) == -1) {
errFinished = true;
}
else {
System.err.print((char) c);
}
}
}
}
System.out.println("End stream read loop.");
}
catch (IOException e) {
throw e;
}
finally {
errReader.close();
inReader.close();
}
}
The problem seems to be that the reading loops are waiting for the streams to report ready, and as a result aren't seeing the -1 returned by read telling them that it's time to quit. I'm trying to avoid having either stream blocking, so that I can pull from both in turn when they are prepared. However, how can I catch the process's end of stream? Am I missing something? Shouldn't read report that it's read when it has an end of stream -1? The processes are finishing, and so their streams should be dying. What am I doing wrong here?
There are two more possibilities:
Use the ProcessBuilder and invoke redirectErrorStream(true) to join the two streams and you need to read one stream. I have an example here.
In JDK7, you could call the inheritIO() to automatically forward everything
Edit On the second guess, it seems the ready() call is misleading your program. Try this:
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
int c = -1;
BufferedReader inReader = new BufferedReader(
new InputStreamReader(in, "US-ASCII"));
BufferedReader errReader = new BufferedReader(
new InputStreamReader(err, "US-ASCII"));
boolean inFinished = false, errFinished = false;
try {
System.out.println("Begin stream read loop...");
if (!inFinished) {
while ((c = inReader.read()) != -1) {
System.out.print((char) c);
}
inFinished = true;
}
if (!errFinished) {
while ((c = errReader.read()) != -1) {
System.err.print((char) c);
}
errFinished = true;
}
System.out.println("End stream read loop.");
}
catch (IOException e) {
throw e;
}
finally {
errReader.close();
inReader.close();
}
}
Or better yet, leave off the BufferedReader if you don't plan any extra transformation:
private void createReader(final InputStream in, final OutputStream out) {
new Thread() {
public void run() {
try {
int c = 0;
while ((c = in.read()) != -1) {
out.write(c);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
in.close();
}
}
}.start();
}
private void forwardStreamtoStd(InputStream in, InputStream err)
throws IOException {
createReader(in, System.out);
createReader(err, System.err);
}
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4090471
The solution I've always used is to create a separate thread to read one of the streams, join on the thread when the main thread finishes reading, and then waitFor the process.
It's essential to consume the 2 streams concurrently, to prevent blocking. See this article for more info, and in particular note the StreamGobbler mechanism that captures stdout/err in separate threads.
If I remember correctly, the spawned process will never close the stream - so you would need to have the readers in their own threads, sleep on the main thread until the process is done, and then close the readers.