nput stream read does not convert all data - java

I am writing application for Android devices, which have to communicate with some other device via bluetooth. (the other device its just a board like Raspery pi with attached bluetooth)
This other device accept list of command which I are single bytes like 'A', 'X', 'C' etc. and when you sending command it always returns some response which is something like 'OK', 'ERROR4' or somethoer data like '0000000000000001230120000000'.
I have implemented most of the command in my application and they work fine. But I have issue with last command which return 1748 bytes. Most of the time I am using this method to getting response, and it works fine:
private String send(byte [] bytes) {
if(bluetoothService == null)
return null;
if(bluetoothSocket == null)
return null;
String line = "";
Log.wtf("BYTESARR", Arrays.toString(bytes));
try {
OutputStream outputStream = bluetoothSocket.getOutputStream();
InputStream inputStream = bluetoothSocket.getInputStream();
outputStream.write(bytes);
outputStream.flush();
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream));
line = r.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return line;
}
But for that command where response is 1748 bytes method above freezing my app. So I implemented second method only for that command, which you see below.
OutputStream outputStream = bluetoothSocket.getOutputStream();
InputStream inputStream = bluetoothSocket.getInputStream();
outputStream.write(bytes);
outputStream.flush();
char [] b = new char[1540];
BufferedReader r = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
int from = 0;
for(int i = 0; i < EXCEPTIONS_NUMBER; i++){
int asdf = r.read(b, from, 50); // from and len are related to B not R
Log.wtf("READ", asdf + " <");
from += asdf;
}
line = new String(b);
Log.wtf("LINE", line);
But problem with that method is my response looks like this: (
...0000000000000������������...
Less then half of this response are 0 (zeros), which is what I was expecting, but second part of this response are those strange question marks(which I believe should be zeros) and I do not know why is that?
Question 1) Why first method making my app freeze when I am reading response with 1748bytes?
Question 2) Why second method is giving me that strange question marks instead of zeros?
EDIT [Solved]
I found the solution. So basically I have to use ByteArrayInputStream like this:
byte [] b = new byte[1538];
ByteArrayInputStream bais = new ByteArrayInputStream(b);
inputStream.read(b);
And that allows me read all bytes from b array and allows me to use bais if needed. I am not sure why this solution works, yet. But I am glad it worked. If someone understand it and can explain would be great. If not I will update post, when find out why it is working, if post will be not closed/deleted.

when you call r.readLine(), the method will not return until one of two conditions is met: the stream returns a line separator character, or the stream signals it has no more data. If neither of those things happen, your app will "freeze" indefinitely.
when you create an array of characters with new char[1540], it's filled with "NUL" characters - a non printing control character with ASCII/Unicode code 0 (don't confuse with "null" object reference in Java). While you read from the stream, you replace some of the content of the array with the characters you read, but some of the original NULs are left in place, and these make it to the string you create later.
To fix, create the string using the portion of the array that you've written to:
line = new String(b, 0, from);

Related

How to split a byte array that contains multiple "lines" in Java?

Say we have a file like so:
one
two
three
(but this file got encrypted)
My crypto method returns the whole file in memory, as a byte[] type.
I know byte arrays don't have a concept of "lines", that's something a Scanner (for example) could have.
I would like to traverse each line, convert it to string and perform my operation on it but I don't know
how to:
Find lines in a byte array
Slice the original byte array to "lines" (I would convert those slices to String, to send to my other methods)
Correctly traverse a byte array, where each iteration is a new "line"
Also: do I need to consider the different OS the file might have been composed in? I know that there is some difference between new lines in Windows and Linux and I don't want my method to work only with one format.
Edit: Following some tips from answers here, I was able to write some code that gets the job done. I still wonder if this code is worthy of keeping or I am doing something that can fail in the future:
byte[] decryptedBytes = doMyCrypto(fileName, accessKey);
ByteArrayInputStream byteArrInStrm = new ByteArrayInputStream(decryptedBytes);
InputStreamReader inStrmReader = new InputStreamReader(byteArrInStrm);
BufferedReader buffReader = new BufferedReader(inStrmReader);
String delimRegex = ",";
String line;
String[] values = null;
while ((line = buffReader.readLine()) != null) {
values = line.split(delimRegex);
if (Objects.equals(values[0], tableKey)) {
return values;
}
}
System.out.println(String.format("No entry with key %s in %s", tableKey, fileName));
return values;
In particular, I was advised to explicitly set the encoding but I was unable to see exactly where?
If you want to stream this, I'd suggest:
Create a ByteArrayInputStream to wrap your array
Wrap that in an InputStreamReader to convert binary data to text - I suggest you explicitly specify the text encoding being used
Create a BufferedReader around that to read a line at a time
Then you can just use:
String line;
while ((line = bufferedReader.readLine()) != null)
{
// Do something with the line
}
BufferedReader handles line breaks from all operating systems.
So something like this:
byte[] data = ...;
ByteArrayInputStream stream = new ByteArrayInputStream(data);
InputStreamReader streamReader = new InputStreamReader(stream, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(streamReader);
String line;
while ((line = bufferedReader.readLine()) != null)
{
System.out.println(line);
}
Note that in general you'd want to use try-with-resources blocks for the streams and readers - but it doesn't matter in this case, because it's just in memory.
As Scott states i would like to see what you came up with so we can help you alter it to fit your needs.
Regarding your last comment about the OS; if you want to support multiple file types you should consider making several functions that support those different file extensions. As far as i know you do need to specify which file and what type of file you are reading with your code.

Is it possible to put a string array into buffered Reader?

I'm working on a project at the moment which requires me to set up a distributed network simulator, I had it working with taking output from a file and parsing through each line with a buffered reader as you can see below but I want to now use a predefined array and make my bufferedReader take input from that instead I've looked up a few solutions online to help me put this array into the buffered Reader but non seem to have worked.
I'm getting no errors when running and terminating the code but just seems to be stuck in an endless loop at some point and I presume it's the new buffered reader segment using the array instead. The idea behind this was to make the process simpler than re-writing many segments to fit around the array parsing and instead find a simpler way by having the array in the buffered Reader but as this is proving difficult I may have to resort to changing. I have tested if the array is being initialised correctly and that's not the problem so it's one less thing to take into consideration.
**Previous code:**
private void parseFile(String fileName) throws IOException {
System.out.println("Parsing Array");
Path path = Paths.get(fileName);
try (BufferedReader br = Files.newBufferedReader(path)) {
String line = null;
line = br.readLine(); // Skip first line
while ((line = br.readLine()) != null) {
parseLine(line);
}
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}
}
The recommendation online was to use an input stream with the buffered reader for it but that didn't seem to work at all as it over wrote the array, any recommendations on what I can use for the buffered reader segment would be grand.
The Array method above is just a void creating the array which is called before the method so the array should be initialised I presume, If anyone can look over and potentially let me know where I'm going wrong and problems that would be amazing if not I appreciate your time to read this anyway, Thanks for your time.
New Code Attempt:
//Creating array to parse.
private void createArray(){
myStringArray[0] = "Node_id Neighbours";
myStringArray[1] = "1 2 10";
myStringArray[2] = "2 3 1";
myStringArray[3] = "3 4 2";
myStringArray[4] = "4 5 3";
myStringArray[5] = "5 6 4";
myStringArray[6] = "6 7 5";
myStringArray[7] = "7 8 6";
myStringArray[8] = "8 9 7";
myStringArray[9] = "9 10 8";
myStringArray[10] = "10 1 9";
myStringArray[11] = "ELECT 1 2 3 4 5 6 7 8 9";
}
private void parseArray() throws IOException {
//InputStreamReader isr = new InputStreamReader(System.in);
System.out.println("Parsing Array");
// try (BufferedReader br = Files.newBufferedReader(path))
try (BufferedReader br = new BufferedReader(isr)) {
for(int i=0;i<12;i++)
{
String line = null;
line = br.readLine(); // Skip first line
while ((myStringArray[i] = br.readLine()) != null) {
parseLine(line);
}
}
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}
}
Answer: You cannot do this with buffered reader. I fixed it like this if this is any use to anyone. Thanks a lot to #L.Spillner for the explanation and answer.
code fix:
private void parseArray() throws IOException {
System.out.println("Parsing Array");
for(int i=1;i<12;i++) //First row ignored.
{
String line = null;
line = myStringArray[i];
//Begin parsing process of each entity.
parseLine(line);
}
}
Let's kick it off with a precise answer to the Question.
You cannot put anything into a BufferedReader directly. Especially when it's some kind of data structure like an array.
The BufferedReader's purpose is to handle I/O Operations, input operations to be more precise. According to the javadoc the BufferedReader takes a Reader as an argument. Reader is an abstract class which contains 'tools' to handle character InputStreams.
The way the BufferedReader's readLine() method works is: Any character arriving on the InputStream gets stored in a buffer until a \n (new line/linefeed) or \r (carriage retun) arrives. When one of these two special characters show up the buffer gets interpreted as a String and is returned to the call.
Answer is you can't. Thanks for the feedback though guys and got it working through just looping through the array and assigning each item to line.

Unable to read the content from a non-empty InputStream

I have a piece of code that reads the content from a non-empty InputStream. However, it works fine in Eclipse and using ant script in my computer, but it fails in an another computer, the result is an empty String, I have checked, the the InputStream is not null. The inputstream is reading a local file, and the file is not empty.
Here are the two different ways I have tried, both of them return an empty String:
Way 1:
StringBuilder aStringBuilder = new StringBuilder();
String strLine = null;
BufferedReader aBufferedReaders = new BufferedReader(new InputStreamReader(anInputStream, "UTF-8"));
while ((strLine = aBufferedReaders.readLine()) != null)
{
aStringBuilder.append(strLine);
}
return aStringBuilder.toString()
Way 2:
StringBuffer buffer = new StringBuffer();
byte[] b = new byte[4096];
for (int n; (n = theInputStream.read(b)) != -1;)
{
buffer.append(new String(b, 0, n));
}
String str = buffer.toString();
return str;
Thanks in advance!
The input stream can be non-null but still empty - and if no exceptions are being thrown but an empty string is being returned, then the input stream is empty. You should look at the code which is opening the input stream in the first place - the code to read from the stream isn't the source of the error, although you need to decide which encoding you're trying to read, and use that appropriately. (The first code looks better to me, explicitly using UTF-8 and using an InputStreamReader for text conversion.)

my code hangs but when i debug it it never hangs

i have a java code that SOMETIMES hangs when i run it.Its a put command that puts through sockets( and input stream etc a file from a server to a client) . Sometimes this works but sometimes it doesnt and i get an error message. i tried every possible path that can be taken through debugging and i can never get it to hang. Is there a way to inspect the thing when its hang through eclipse?`
if (sentence.length() > 3 && sentence.substring(0, 3).equals("put")) {
File checkFile = new File(dir.getCurrentPath(), sentence.substring(4));
if (checkFile.isFile() && checkFile.exists()) {
try {
outToServer.writeBytes(sentence + "\n");
boolean cont = false;
String x;
while (!cont) {
if ((x = inFromServer.readLine()).equals("continue")) {
cont = true;
}
}
String name = sentence.substring(4);
copy.copyFile(name);
// outToServer.writeBytes("continue" + "\n");
this is the client code that recieves the PUT request(i.e. put test.txt takes the file test.txt and puts it in the server's local dir.
Copy file: (the thing that copies the data)
File checkFile = new File(dir.getCurrentPath(), file);
if (checkFile.isFile() && checkFile.exists()) {
DataOutputStream outToClient = new DataOutputStream(socket.getOutputStream());
// byte[] receivedData = new byte[8192];
File inputFile = new File(dir.getCurrentPath(), file);
byte[] receivedData = new byte[(int) inputFile.length()];
// String theLength = "" + inputFile.length();
outToClient.writeBytes("" + inputFile.length() + "\n");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(getCopyPath(file)));
// if (extension.equals("")) {
// extension = "txt";
// }
// BufferedReader inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// boolean cont = false;
// while (!cont) {
// if (inFromClient.readLine().equals("continue")) {
// cont = true;
//
// }
// }
// outToClient.writeBytes("continue" + "\n");
bis.read(receivedData, 0, receivedData.length);
OutputStream os = socket.getOutputStream();
os.write(receivedData, 0, receivedData.length);
// outToClient.writeBytes("finish" + "\n");
os.flush();
Protocol on server(copies stuff in the file)
if (get.equals("put")) {
//so the client sends: the put request
//then sends the length
try {
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(socket.getInputStream()));
DataOutputStream outToClient = new DataOutputStream(socket.getOutputStream());
outToClient.writeBytes("continue" + "\n");
int length = Integer.parseInt(inFromClient.readLine());
// String x = "";
// boolean cont = false;
// while (!cont) {
// String temp = inFromClient.readLine();
// if (temp.equals("finish")) {
// cont = true;
// }
// else {
// x += temp;
// }
// }
byte[] recieveFile = new byte[length];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("Copy " + input.substring(4));
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead;
int current = 0;
bytesRead = is.read(recieveFile, 0, recieveFile.length);
current = bytesRead;
If you cant answer the question in specific just tell me how i can debug the code that hangs or how i can debug concurrent code.(by the way the way that the signal passing is done is by passing a token as you can see i.e. the server sents a continue token that tells the client to start sending data, i havent done this with threads methods notify and wait since i cant use , since any single object has only 1 method.
when your process hangs, get the current stack dump for the process. this will show you why the process is hung.
note, you have at least one bug in your program, in that you are not handling the return value from the InputStream.read() method which will, at the very least, cause you to have busted data on the server side. (see #rk2010's answer for more details).
you main bug, though, is that when you wrap the BufferedReader around the socket InputStream, you are probably going to end up "stealing" more bytes from the stream than the just length value. when a BufferedReader reads data from the underlying stream, it can read more data than it actually returns in the readLine() method (so, it may read 1000 chars internally, but the first "line" may only contain 20 chars). if you continue to use the BufferedReader, everything is fine, but if you discard the BufferedReader and try to read more data from the underlying stream, you will have less data there than you expect. so, when you go to read the file contents, there aren't enough bytes available.
instead, you should be using DataOutputStream/DataInputStream exclusively. write the length as a long value (i.e. DataOutputStream.writeLong(long)), then write the bytes after (i.e. DataOutputStream.write(byte[])). then read the data using the corresponding methods in DataInputStream. since you can use the DataInputStream exclusively when reading (first to read the file size and then to read the actual file bytes), you don't risk losing bytes when switching read "modes" (additionally, DataInputStream does not do any internal buffering like BufferedReader). don't use Readers/Writers at all.
add logging after every read and write command. Give each thread a name.
run the program, see how the log matches up with what you expect.
note that you can't always rely on read method like the way you are. Safe way to read is by looping until you get a negative length.
int len = -1;
byte[] buff = new byte[1024]; // for 4KB, use: 4* 1024
while ( (len = is.read(buff, 0, buff.length)) > -1){
// copy len number of bytes from buff array into some other place.
}
Check out IOUtils.copy method
from Apache Commons IOUtils class

Capture data read from file into string stream Java

I'm coming from a C++ background, so be kind on my n00bish queries...
I'd like to read data from an input file and store it in a stringstream. I can accomplish this in an easy way in C++ using stringstreams. I'm a bit lost trying to do the same in Java.
Following is a crude code/way I've developed where I'm storing the data read line-by-line in a string array. I need to use a string stream to capture my data into (rather than use a string array).. Any help?
char dataCharArray[] = new char[2];
int marker=0;
String inputLine;
String temp_to_write_data[] = new String[100];
// Now, read from output_x into stringstream
FileInputStream fstream = new FileInputStream("output_" + dataCharArray[0]);
// Convert our input stream to a BufferedReader
BufferedReader in = new BufferedReader (new InputStreamReader(fstream));
// Continue to read lines while there are still some left to read
while ((inputLine = in.readLine()) != null )
{
// Print file line to screen
// System.out.println (inputLine);
temp_to_write_data[marker] = inputLine;
marker++;
}
EDIT:
I think what I really wanted was a StringBuffer.
I need to read data from a file (into a StringBuffer, probably) and write/transfer all the data back to another file.
In Java, first preference should always be given to buying code from the library houses:
http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html
http://commons.apache.org/io/api-1.4/org/apache/commons/io/FileUtils.html
In short, what you need is this:
FileUtils.readFileToString(File file)
StringBuffer is one answer, but if you're just writing it to another file, then you can just open an OutputStream and write it directly out to the other file. Holding a whole file in memory is probably not a good idea.
In you simply want to read a file and write another one:
BufferedInputStream in = new BufferedInputStream( new FileInputStream( "in.txt" ) );
BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream( "out.txt" ) );
int b;
while ( (b = in.read()) != -1 ) {
out.write( b );
}
If you want to read a file into a string:
StringWriter out = new StringWriter();
BufferedReader in = new BufferedReader( new FileReader( "in.txt" ) );
int c;
while ( (c = in.read()) != -1 ) {
out.write( c );
}
StringBuffer buf = out.getBuffer();
This can be made more efficient if you read using byte arrays. But I recommend that you use the excellent apache common-io. IOUtils (http://commons.apache.org/io/api-1.4/org/apache/commons/io/IOUtils.html) will do the loop for you.
Also, you should remember to close the streams.
I also come from C++, and I was looking for a class similar to the C++ 'StringStreamReader', but I couldn't find it. In my case (which I think was very simple), I was trying to read a file line by line and then read a String and an Integer from each of these lines. My final solution was to use two objects of the class java.util.Scanner, so that I could use one of them to read the lines of the file directly to a String and use the second one to re-read the content of each line (now in the String) to the variables (a new String and a positive 'int'). Here's my code:
try {
//"path" is a String containing the path of the file we want to read
Scanner sc = new Scanner(new BufferedReader(new FileReader(new File(path))));
while (sc.hasNextLine()) { //while the file isn't over
Scanner scLine = new Scanner(sc.nextLine());
//sc.nextLine() returns the next line of the file into a String
//scLine will now proceed to scan (i.e. analyze) the content of the string
//and identify the string and the positive 'int' (what in C++ would be an 'unsigned int')
String s = scLine.next(); //this returns the string wanted
int x;
if (!scLine.hasNextInt() || (x = scLine.nextInt()) < 0) return false;
//scLine.hasNextInt() analyzes if the following pattern can be interpreted as an int
//scLine.nextInt() reads the int, and then we check if it is positive or not
//AT THIS POINT, WE ALREADY HAVE THE VARIABLES WANTED AND WE CAN DO
//WHATEVER WE WANT WITH THEM
//in my case, I put them into a HashMap called 'hm'
hm.put(s, x);
}
sc.close();
//we finally close the scanner to point out that we won't need it again 'till the next time
} catch (Exception e) {
return false;
}
return true;
Hope that helped.

Categories