Java - Differenciate between two Strings sent into OustputStream - java

I'm sending 2 String values into an OutputStream from the Client.java as follows :
outputStream.write(username.getText().getBytes());
outputStream.write(password.getText().getBytes());
In the Server.java, i'm trying to get each value separated, when i read the inputStream :
inputStream = s.getInputStream();
byte[]username = new byte[20];
inputStream.read(username);
String user = new String(username);
System.out.println("username = "+user);
i get logically : usernamepassword as the console output.
what i want to do is :
String usr = new String(user);
String pass = new String(password);
Is there a better way to do it than adding some delimiter in the outputStream String ?

You need to delimit the two string values so the reader knows where one string ends and the next string begins. What that delimiter actually consists of is up to you to decide based on your particular needs.
You could write out a string's byte length using a fixed-width integer before then writing out the actual bytes. The reader can then read the length first before then reading the specified number of bytes that follow:
DataOutputStream dos = new DataOutputStream(outputStream);
byte[] bytes;
int len;
bytes = username.getText().getBytes(StandardCharsets.UTF_8);
len = bytes.length;
dos.writeInt(len);
dos.write(bytes, 0, len);
bytes = password.getText().getBytes(StandardCharsets.UTF_8);
len = bytes.length;
dos.writeInt(len);
dos.write(bytes, 0, len);
inputStream = s.getInputStream();
DataInputStream dis = new DataInputStream(inputStream);
byte[] bytes;
int len;
len = dis.readInt();
bytes = new byte[len];
dis.readFully(bytes);
String username = new String(bytes, StandardCharsets.UTF_8);
len = dis.readInt();
bytes = new byte[len];
dis.readFully(bytes);
String password = new String(bytes, StandardCharsets.UTF_8);
Alternatively, DataOutputStream and DataInputStream can write/read String values directly, handling the above logic internally for you (using a short instead of an int for the length value):
DataOutputStream dos = new DataOutputStream(outputStream);
dos.writeUTF(username.getText());
dos.writeUTF(password.getText());
inputStream = s.getInputStream();
DataInputStream dis = new DataInputStream(inputStream);
String username = dis.readUTF();
String password = dis.readUTF();
you could write out a unique character sequence that will never appear in the string values themselves, such as a line break or control character (even a null terminator). The reader can then read bytes until it encounters that sequence:
OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
String s;
s = username.getText();
writer.write(s, 0, s.length());
writer.write(10);
s = password.getText();
writer.write(s, 0, s.length());
writer.write(10);
inputStream = s.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String username = reader.readLine();
String password = reader.readLine();
Alternatively:
OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
String s;
s = username.getText();
writer.write(s, 0, s.length());
writer.write(0);
s = password.getText();
writer.write(s, 0, s.length());
writer.write(0);
inputStream = s.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
int ch;
do
{
ch = reader.read();
if (ch <= 0) break;
sb.append((char)ch);
}
while (true);
String username = sb.toString();
sb.setLength(0);
do
{
ch = reader.read();
if (ch <= 0) break;
sb.append((char)ch);
}
while (true);
String password = sb.toString();

I would go for DataOutputStream for writing and the DataInputStream for reading. With those, you can write an integer value before each String to know the length of the text, something like this:
DataOutputStream dos = new DataOutputStream(outputStream);
dos.writeInt(username.getText().length());
dos.write(username.getText().getBytes());
dos.writeInt(password.getText().length());
dos.write(password.getText().getBytes());
And then, on the server side:
DataInputStream dis = new DataInputStream(inputStream);
int length = 0; // will be used to store the length of each text
length = bytesRead = dis.readInt(); // Read the length of the first text
byte[] usernameBuffer = new byte[length];
dis.read(usernameBuffer);
String username = new String(usernameBuffer);
// Now reading the other text
length = dis.readInt(); // Read the length of the second text
byte[] passwordBuffer = new byte[length];
dis.read(passwordBuffer);
String password = new String(passwordBuffer);

Related

Fast way to read file from input stream when we know the size with low memory usage

Is there any faster way to read from an inputstream when we know the size of the data?
This code that I have is very slow:
File file = new File("file.jar");
if(!file.exists)file.createNewFile();
String url = "https://launcher.mojang.com/v1/objects/3870888a6c3d349d3771a3e9d16c9bf5e076b908/client.jar";
int len = 8461484;
InputStream is = new URL(url).openStream();
if(!file.exists())
file.createNewFile();
PrintWriter writer = new PrintWriter(file);
for(long i = 0;i < len;i ++) {
writer.write(is.read());
writer.flush();
System.out.println(i);
}
writer.close();
Use Buffered Input & Output Streams together with try-with-resources
(which ensures the Streams are all closed at EOJ)
Something like this:
try(final InputStream ist = new URL(url).openStream ();
final InputStream bis = new BufferedInputStream (ist);
final OutputStream ost = new FileOutputStream(file);
final OutputStream bos = new BufferedOutputStream(ost))
{
final byte[] bytes = new byte[64_000]; // <- as large as possible!
/**/ int count;
while ((count = bis.read(bytes)) != -1) {
bos.write(bytes, 0, count);
}
}

How to decode bytes from file that contains strings in java?

I have a file that contains a string followed by bytes that contain binary numbers encoded in them.
Thisisastring. �J
In my code I try to ignore the string and focus on decoding the bytes that are separated by a space. When I run the code the outcome seems to be correct except the first binary number is off by a lot.
StringBuffer buffer = new StringBuffer();
File file = new File(arg);
FileInputStream in = new FileInputStream(file);
InputStreamReader isr = new InputStreamReader(in, "UTF8");
Reader inn = new BufferedReader(isr);
int ch;
while ((ch = inn.read()) > -1){
buffer.append((char)ch);
}
inn.close();
String content = buffer.toString();
String temp = new String();
for(int i=0; i<content.length(); i++){
temp += content.charAt(i);
if(content.charAt(i) == ' '){
while(i != content.length()-1){
i++;
byte b = (byte) content.charAt(i);
String x = Integer.toString(b & 0xFF, 2);
System.out.println(x);
}
}
}
Results:
11111101 <- Why is only this one incorrect?
11000
1001010
1011
What is expected:
10010101
00011000
01001010
1011
You should not use Readers or Strings for binary data.
StringBuffer buffer = new StringBuffer();
File file = new File(arg);
FileInputStream in = new FileInputStream(file);
DataInputStream dis = new DataInputStream(new BufferedInputStream(in));
int ch;
while ((ch = din.read()) > -1){
buffer.append((char)ch);
if (ch == ' ')
{
// next byte is a binary value
byte b = din.readByte();
String x = Integer.toString(b & 0xFF, 2);
System.out.println(x);
}
}

How to get the file name from an RRQ datagramPacket?

Im working on a TFTP server. Basing on the image the max length of my packets is 516 bytes (2+2+512).
I'm trying to take the original length from the client datagrampacket(in this case sends 13 bytes in a RRQ packet), instead im getting the server datagrampacket length (516 bytes) where i save the client datagrampacket.
I need that for extract the filename, i did that but the string content is "filename + nullBytes", those null bytes come from the server datagrampacket.
This is the code where im stuck:
public static short RRQ = 1;
enter code here
public void dataMetod() throws IOException{
byte[] packet = new byte[516];
//socket with listening port 5000
DatagramSocket datagramSocket = new DatagramSocket(5000);
//while receive packets
while (true) {
DatagramPacket datagramPacket = new DatagramPacket(packet,packet.length);
datagramSocket.receive(datagramPacket);
System.out.println("server: new packet!!:");
//create a byte[] with the "received packet length"(that's not true)
byte[] inData = new byte[datagramPacket.getLength()];
inData = datagramPacket.getData();
System.out.println("length: "+inData.length);
byte code;
code = inData[1];
System.out.println(code);
//check if its an RRQ packet
if (code == RRQ) {
System.out.println("server: RRQ PACKET!!");
String fileName = this.getFileName(inData);
System.out.println(fileName);
}
public String getFileName(byte[] inData) {
byte[] aux = new byte[inData.length - 7];
for (int i = 0; i < aux.length; i++) {
aux[i] = inData[i + 2];
}
return new String(aux);
}
http://i.stack.imgur.com/6dTH6.png
Try this:
public String getFileName(byte[] inData) {
final int maxLen = inData.length;
final StringBuilder sb = new StringBuilder();
int i = 2;
byte b;
while ( (i < maxLen) && (b = inData[i]) != 0 ) {
final int v = ((int)b) & 0xff;
sb.append( (char) v );
i++;
}
return sb.toString();
}
Instead of getting the original length of the received packet(to search the file name through the array), we could do that by adding "\n" at fileName String in client class, then use BufferedReader which will detect "\n" and save the fileName.
Code:
public String getFileName(byte[] inData) throws IOException {
//get a sub-array, from index[2] (beacuse we dont want opCode) to inData length
byte[] b =Arrays.copyOfRange(inData, 2, inData.length);
InputStream is = new ByteArrayInputStream(b);
BufferedReader bf = new BufferedReader(new InputStreamReader(is));
//We read a word that will be saved when "\n" is found.
//(adding "\n" previously to the fileName String in client class)
String filename = bf.readLine();
bf.close();
is.close();
System.out.println("server: filename is: "+filename.length()+" bytes");
return filename;
}

HttpURLConnection output to byte array then to String

I'm reading a response from an HttpURLConnection object to a String like so:
HttpURLConnection conn = ...;
BufferedReader rd = new BufferedReader(new InputStreamReader(
conn.getInputStream());
StringBuilder sb = ...;
String line = "";
while ((line = rd.readLine()) != null) {
sb.append(line);
}
String asString = sb.toString();
If I want to read instead to a byte array first, then convert that byte array to a String, what's the right way to do it?
InputStream is = conn.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream(16384);
byte[] buf = new byte[512];
while (true) {
int len = in.read(buf);
if (len == -1) {
break;
}
baos.write(buf, 0, len);
}
byte[] out = baos.toByteArray();
// as a string:
String asString = new String(out);
but I'm not specifying the character in either case - are the two String outputs at the end of the examples equivalent?
Thanks

Append part of Java byte array to StringBuilder

How do I append a portion of byte array to a StringBuilder object under Java? I have a segment of a function that reads from an InputStream into a byte array. I then want to append whatever I read into a StringBuilder object:
byte[] buffer = new byte[4096];
InputStream is;
//
//some setup code
//
while (is.available() > 0)
{
int len = is.read(buffer);
//I want to append buffer[0] to buffer[len] into StringBuilder at this point
}
You should not use a StringBuilder for this, since this can cause encoding errors for variable-width encodings. You can use a java.io.ByteArrayOutputStream instead, and convert it to a string when all data has been read:
byte[] buffer = new byte[4096];
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream is;
//
//some setup code
//
while (is.available() > 0) {
int len = is.read(buffer);
out.write(buffer, 0, len);
}
String result = out.toString("UTF-8"); // for instance
If the encoding is known not to contain multi-byte sequences (you are working with ASCII data, for instance), then using a StringBuilder will work.
You could just create a String out of your buffer:
String s = new String(buffer, 0, len);
Then if you need to you can just append it to a StringBuilder.
Something like below should do the trick for you.
byte[] buffer = new byte[3];
buffer[0] = 'a';
buffer[1] = 'b';
buffer[2] = 'c';
StringBuilder sb = new StringBuilder(new String(buffer,0,buffer.length-1));
System.out.println("buffer has:"+sb.toString()); //prints ab

Categories

Resources