I would like to get data from InputStream() as a String eg. Hi, Start, Stop, etc.
My Code fragment is
byte[] buffer = new byte[1024];
inputStream.read(buffer);
My data is Command Sent from Bluetooth.
The above code fragment only get (eg. 2 if I sent Hi, 5 if sent Start), I would like to get back Normal String as the same from the Sender Side.
I found only converting way from String to InputStream.
any suggestion , I would like to appreciate!
finally, i can solve this!
inputStream.read(buffer); only return the int num of how many bytes is in the buffer and the data from the socket is stored in buffer. So, from the buffer you can make String
eg. String result = new String (buffer);
The simplest way is via the Apache common-io library:
String input = IOUtils.toString(inputStream);
See the javadoc for this method for more.
Related
I tried to send an image from One device to other Device using Bluetooth.For that I take Android Bluetooth chat application source code and it works fine when I send String.But If i send image as byte array the while loop not breaks or EOF not reached when read from Inputstream.
Model:1
It receives image properly.But here I need to pass resultByteArray length.But I dont know the length.How to know the length of byte array in inputstream? inputstream.available() returns 0.
while(true)
{
byte[] resultByteArray = new byte[150827];
DataInputStream dataInputStream = new DataInputStream(mmInStream);
dataInputStream.readFully(resultByteArray);
mHandler.obtainMessage(AppConstants.MESSAGE_READ, dataInputStream.available(),-1, resultByteArray).sendToTarget();
}
Model:2
In this code while loop not breaks,
ByteArrayOutputStream bao = new ByteArrayOutputStream();
byte[] resultByteArray = new byte[1024];
int bytesRead;
while ((bytesRead = mmInStream.read(resultByteArray)) != -1) {
Log.i("BTTest1", "bytesRead=>"+bytesRead);
bao.write(resultByteArray,0,bytesRead);
}
final byte[] data = bao.toByteArray();
Also tried byte[] resultByteArray = IOUtils.toByteArray(mmInStream);but it also not works.I followed Bluetooth chat sample.
How to solve this issue?
As noted in the comment, the server needs to put the length of image at front of the actual image data. And the length of the image length information should be fixed like 4 bytes.
Then in the while loop, you need to get 4 bytes first to figure out the length of the image. After that, read bytes of the exact length from the input stream. That is the actual image.
The while loop doesn't need to break during the connection is alive. Actually it needs to wait another image data in the same while loop. The InputStream.read() is a blocking function and the thread will be sleeping until it receives enough data from the input stream.
And then you can expect another 4 bytes right after the previous image data as a start of another image.
while(true) {
try {
// Get the length first
byte[] bytesLengthOfImage = new byte[4];
mmInStream.read(bytesLengthOfImage);
int lengthOfImage = 0;
{
ByteBuffer buffer = ByteBuffer.wrap(bytesLengthOfImage);
buffer.order(ByteOrder.BIG_ENDIAN); // Assume it is network byte order.
lengthOfImage = buffer.getInt();
}
byte[] actualImage = new byte[lengthOfImage]; // Mind the memory allocation.
mmInStream.read(actualImage);
mHandler.obtainMessage(AppConstants.MESSAGE_READ, lengthOfImage,-1, actualImage).sendToTarget();
} catch (Exception e) {
if(e instanceof IOException) {
// If the connection is closed, break the loop.
break;
}
else {
// Handle errors
break;
}
}
}
This is a kind of simplified communication protocol. There is an open source framework for easy protocol implementation, called NFCommunicator.
https://github.com/Neofect/NFCommunicator
It might be an over specificiation for a simple project, but is worth a look.
I'm trying to get a very simple Client-Server system to work, where the Client will send a String over to the Server, and the server will then store that String into a file.
The client sends the string through:
//Other Code
sockStrm = new DataOutputStream (clientSocket.getOutputStream ());
//Other code
sockStrm.writeChars (line);
//Other code
And the Server receives the String with:
//Other code
strm = new BufferedReader (new InputStreamReader (clientSocket.getInputStream ()));
//Other code
stringLine = strm.readLine ();
//Other code
When I send the string STOP, the length of the String is 4 on the client side, and on the server side the length of the String is 9 and displays as STOP
I've tried to substring the received String on the Server side, without luck.
Any pointers on how to deal with this?
Use symmetric methods:
DataOutputStream sockStrm =...
sockStrm.writeUTF(str);
and
DataInputStream sockStrm = ...
String str = sockStrm.readUTF();
writeChars writes individual characters as two byte values. Readers follow the encoding to reconstruct the string from a sequence of bytes, which will definitely not be according to high-byte-low-byte for each character code. Hence you get some mish-mash of zero bytes with the original low-byte values so you still have a glimpse of the original string value.
Using \x00 to denote a NULL byte:
S-T-O-P => on the line: \x00-S-\x00-T-\x00-O-\x00-P => prints as STOP
Use a loop over the characters of the incoming string and display their integer values (str.charAt(i)) to see the above for yourself.
Sever code
if(success){
out.write("true".getBytes().length);
out.write("true".getBytes());
out.flush();
}
else{
out.write("false".getBytes().length);
out.write("false".getBytes());
out.flush();
}
Client Code
int size = inputStream.read();
byte[] buf = new byte[size];
inputStream.read(buf);
ns = new String(buf);
Boolean.valueOf(ns);
Although the sever send the result client read it wrong. What is the problem in here? how can i solve it. As example sever send value true but client receive it as false
You need to step thread what you are doing exactly. Obviously the simplest way to sent a boolean is as a single byte like this.
out.write(success ? 1 : 0);
and to read this you would do
boolean success = in.read() != 0;
However, if you need to send a string, I would check what string you are reading and what the correct length is, because there is any number of reasons a binary protocol can fail, e.g. because the previous thing you read/wrote was incorrect.
Server and Client are probably using different charsets.
Use an explicit one (and the same) in both sides.
see http://docs.oracle.com/javase/6/docs/api/java/lang/String.html
public byte[] getBytes(String charsetName)
throws UnsupportedEncodingException
and
public String(byte[] bytes,
String charsetName)
throws UnsupportedEncodingException
I am using dataInputStream's readFully message to read a fixed length byte array as:
byte[] record = new byte[4660004];
in.readFully(record);
The problem here is that sometimes it takes more than 5 seconds to read these many bytes, which is equal to 20000 records. And I am receiving this data on socket. Client is sending data as byte array of 4660004 bytes. Is there a way to received this data faster as right now it takes about 5 minutes to 1 million such records.
EDIT:: complete data flow :
first I create the stream :
static DataInputStream dIn = null;
dIn = new DataInputStream(connection.getInputStream());
msgType = dIn.readByte();
int msgIntLen = dIn.readInt();
processBatch(msgIntType, msgIntLen, dIn, connector);
.
.
private static void processBatch(int msgIntType, int msgIntLen, DataInputStream in,
Connector connector) throws IOException {
int recordIntLen = in.readInt();
byte[] record = new byte[msgIntLen - 4];
in.readFully(record);
}
where should I include the Buffering if that wudf help ?
Comments are beginning to scroll, so moving to an answer.
Buffer your output on the client side by using a BufferedOutputStream. Make sure to call dlOut.flush() after writing the data, so that unsent bytes don't remain in the buffered output stream.
Buffer your input on the client side by using a BufferedInputStream.
Because you are just sending byte arrays, you probably don't need the DataInputStream/DataOuputStream, unless you are using them for an additional purpose. You could just be using BufferedInputStream/BufferedOutputStream.
NOW here is the coding for j2me mobile for sending the string:
String s="hai";
try{
String url = "btspp://001F81000250:1;authenticate=false;encrypt=false;master=false";
StreamConnection stream = null;
InputStream in;
OutputStream out;
stream = (StreamConnection) Connector.open(url);
out=stream.openOutputStream();
String s=tf.getString();
byte size=(byte) s.length();
out.write(size);
out.write(s.getBytes());
out.flush();
out.close();
stream.close();
}
catch(Exception e){
}
NOW the coding for j2se for receiving the String :
StreamConnectionNotifier notifier=null;
try{
String url = "btspp://localhost:"+new UUID("1101", true).toString()+";name=PCServerCOMM;authenticate=false";
System.out.println(LocalDevice.getLocalDevice().getBluetoothAddress()+"\nCreate server by uri: " + url);
notifier= (StreamConnectionNotifier) Connector.open(url);
while(true){
System.out.println("waiting....");
StreamConnection con = notifier.acceptAndOpen();
System.out.println("Got connection..");
InputStream is=con.openInputStream();
//byte b[]=new byte[40];
/*
while(is.available()>0){
System.out.print((char)is.read());
}*/
//is.read(b, 0, 40);
int size=is.read();
byte b[]=new byte[size];
is.read(b, 0, size);
File f=new File("d://test.xml");
FileOutputStream fo=new FileOutputStream(f);
fo.write(b,0,b.length);
fo.close();
con.close();
System.out.println(new String (b));
}
//printing(f);
} catch(Exception e){
JOptionPane.showConfirmDialog(new JFrame(), e.getMessage());
}
I tried this coding for data transfer but it is not a successful one because when the string which we sent is too long then there is problem in receiving side. How can I solve this?
Is there any other way to transfer the data in rms to j2se, if so please help me.... please make your reply quick...
The way you are writing and reading here, only strings up to 255 characters in length, which additionally only take the same number of bytes in your default encoding, are written right.
On the writing side:
The statement byte size=(byte) s.length(); converts the length of the string in a byte, thus only takes the lower 8 bits of the length. So, only lengths up to 255 are written right.
Then you are converting the String to a byte array with s.getBytes() - this array could be longer (in bytes) than the original string in characters. This conversion uses the default encoding of your sending device.
On the reading side:
The statement int size=is.read(); reads the length written before, then you are creating a byte array.
is.read(b, 0, size); reads some bytes into this array - it does not necessarily fills the complete array.
Then you are converting your byte array (which may not even be filled completely) to a string, using the default encoding of the receiving device.
So, we have:
All strings longer than 255 characters are written wrongly.
If sending and receiving side are using different encodings, you may get a wrong output.
If the sending side uses an encoding like UTF-8 where some characters take more than one byte, the string is cut off at the end (if such characters occur).
How to solve this:
If you can use a DataInputStream and DataOutputStream on both sides (I don't know anything about J2ME), use them there, with their readUTF and writeUTF methods. They solve all your problems (if your strings take at most 65535 bytes in the modified UTF-8 encoding used here).
If not:
make a decision on how long the strings can be, and encode your length with the right number of bytes. 4 bytes are enough for every Java String.
measure the length after converting to a byte[], not before.
use a loop for reading into the array, to be sure to capture the whole string.
for the getBytes() and new String(...), use the variants which take an explicit encoding name and give them the same encoding (I recommend "UTF-8").