Retrieving data from byte Array - java

I'm trying to implement the tail program and want to print the last n bytes of a file. I've used a RandomAccessFile variable to store the data from the text file. When I try to retrieve the data and print it to the console, I'm getting something like this:
-n1
65109710979710979710810979710810510510979710910659711010510979711410011897114107109797114100119111108102106597114111110
How does on properly retrieve the data from the byte array?
This is my code:
RandomAccessFile raf = new RandomAccessFile(file, "r");
byte[] b = new byte[n];
raf.readFully(b, 0, n);
for (int i = 0; i < n; i++) {
System.out.print(b[i]);
}

You are printing the byte value. To convert e.g. an array of bytes to a String that you can print on System.out.println try the following:
System.out.println(new String(b));
If you wish to convert each byte (as in your loop) to a printable charyou can do the following conversion:
for (int i = 0; i < 10; i++) {
char c = (char) (b[i] & 0xFF);
System.out.print(c);
}
A byte is simply one byte in size (8 bits) whereas a char in Java i 16 bits (2 bytes). Therefore the printed bytes does not make sense, it is not an entire character.
See this link for more info.

Related

Wireshark hex dump analyzer possible to do in Java?

I have a pcap file and I can view the hex and human-readable string equivalent of the hexdump using wireshark. However, I want to do the same but in Java. Here is a screenshot from Wireshark application.
Taking the highlighted string, this is what i've come but the output is not what I've expect. Can someone help me? Thank you very much
String hex = "a106020110020138";
byte[] bts = new byte[hex.length() / 2];
for (int i = 0; i < bts.length; i++) {
bts[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
}
String c = new String(bts, StandardCharsets.US_ASCII);
System.out.println(c);
This is the output:
Java uses UTF-16 for characters, in what byte order i forgot, meaning you need to use two bytes per character.
If you want the output to look exactly like Wireshark's, you can do by reading each group of two hex digits, and keeping that ones that correspond to printable ASCII characters:
public class Pcap {
public static void main(String[] args) {
String hex = "701c2f676c08a106020110020138";
int n = hex.length();
char[] cs = new char[n / 2];
for (int i = 0; i < n; i+=2)
cs[i/2] = (char) Integer.parseInt(hex.substring(i, i+2), 16);
for (int i = 0; i < cs.length; i++)
if (cs[i] < ' ' || cs[i] > '~') // printable ASCII
cs[i] = '.';
System.out.println(new String(cs));
}
}
which outputs
p./gl........8
However, my guess is that you're better off using a library that can parse pcaps (I mentioned one earlier, it looks like http://jpcap.sourceforge.net might also work), since just getting that hex string in the first place required opening Wireshark. You can write the code yourself to pull those values from the (binary) pcap file, but projects already exist to do that.

Read 32 bit binary numbers in java

I am trying to read five 32-bit binary numbers and print them as int. Here is my code:
FileInputStream fin = new FileInputStream(file);
int count = 5;
for (int i = 0; i < count; i++) {
byte[] input = file.getBytes();
String bin=Integer.toBinaryString(0xFF & input[i] | 0x100).substring(1);
System.out.println(bin);
I am getting this:
01010011
01101110
00110011
01011111
01010010
What am I doing wrong? thanks
You're not actually reading from the file, but printing the binary representation of the first five characters of the name of the file. Use fin.read() to read bytes from the file.
You can also use DataInputStream to read 32 bit big endian integers directly, instead of reading them as 4 individual bytes.
If you need to read five big-endian 32-bit integers, then I suggest that you use DataInputStream, e.g.
final int count = 5;
try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
for (int i = 0; i < count; i++) {
int value = dis.readInt();
System.out.println(Integer.toBinaryString(value));
}
}

How to convert string into bits and then into int array - java

How to convert string into bits(not bytes) or array of bits in Java(i will do some operations later) and how to convert into array of ints(every 32 bits turn into the int and then put it into the array? I have never done this kind of conversion in Java.
String->array of bits->(some operations I'll handle them)->array of ints
ByteBuffer bytes = ByteBuffer.wrap(string.getBytes(charset));
// you must specify a charset
IntBuffer ints = bytes.asIntBuffer();
int numInts = ints.remaining();
int[] result = new int[numInts];
ints.get(result);
THIS IS THE ANSWER
String s = "foo";
byte[] bytes = s.getBytes();
StringBuilder binary = new StringBuilder();
for (byte b : bytes)
{
int val = b;
for (int i = 0; i < 8; i++)
{
binary.append((val & 128) == 0 ? 0 : 1);
val <<= 1;
}
// binary.append(' ');
}
System.out.println("'" + s + "' to binary: " + binary);
You are looking for this:
string.getBytes();
Not list, it's an array but you can use it later on, even to convert it to integers.
Well, maybe you can skip the String to bits conversion and convert directly to an array of ints (if what you want is the UNICODE value of each character), using s.toCharArray() where s is a String variable.
This will convert "abc" to byte and then the code will print "abc" in respective ASCII code (ie. 97 98 99).
byte a[]=new byte[160];
String s="abc";
a=s.getBytes();
for(int i=0;i<s.length();i++)
{
System.out.print(a[i]+" ");
}
May be so (I have no compiler in my current computer and don't test if it work, but it can help you a bit):
String st="this is a string";
byte[] bytes=st.getBytes();
List<Integer> ints=new ArrayList<Integer>();
ints.addAll(bytes);
If compiler fails in
ints.addAll(bytes);
you can replace it with
for (int i=0;i<bytes.length();i++){
ints.add(bytes[i]);
}
and if you want to get exactly array:
ints.toArray();
Note that string is a sequence of chars, and in Java each char data type is a single 16-bit Unicode character. It has a minimum value of '\u0000' (or 0) and a maximum value of '\uffff' (or 65,535 inclusive). In order to get char integer value do this:
String str="test";
String tmp="";
int result[]=new int[str.length()/2+str.length()%2];
int count=0;
for(char c:str.toCharArray()) {
tmp+=Integer.toBinaryString((int)c);
if(tmp.length()==14) {
result[count++]=Integer.valueOf(tmp,2);
//System.out.println(tmp+":"+result[count-1]);
tmp="";
}
}
for(int i:result) {
System.out.print(i+" ");
}

Converting array with samples into byte array

I have two-dimensional array of integers. First index indicates the number of channels. The second one indicates the number of sample in the channel. How can I save this array into the audio file? I know, I have to convert it to byte array, but I have no idea how to do that.
// edit
More info. I already have a class for drawing a waveform. It is here:
http://javafaq.nu/java-example-code-716.html
now I want to cut part of this wave and save it to the new file. So I have to cut part of int[][] samplesContainer, convert it to byte array (I don't know how) and then save it to file with the same format as audioInputStream.
// edit
OK. So the biggest problem is to write inverted function to this one:
protected int[][] getSampleArray(byte[] eightBitByteArray) {
int[][] toReturn = new int[getNumberOfChannels()][eightBitByteArray.length / (2 * getNumberOfChannels())];
int index = 0;
//loop through the byte[]
for (int t = 0; t < eightBitByteArray.length;) {
//for each iteration, loop through the channels
for (int a = 0; a < getNumberOfChannels(); a++) {
//do the byte to sample conversion
//see AmplitudeEditor for more info
int low = (int) eightBitByteArray[t];
t++;
int high = (int) eightBitByteArray[t];
t++;
int sample = (high << 8) + (low & 0x00ff);
if (sample < sampleMin) {
sampleMin = sample;
} else if (sample > sampleMax) {
sampleMax = sample;
}
//set the value.
toReturn[a][index] = sample;
}
index++;
}
return toReturn;
}
I don't understand why there is second incrementation of t, after high. I also have no idea how can i get high and low from sample.
The code you posted reads a sample stream, byte by byte, into the samples array. The code assumes that, in the stream, every two 8-bit bytes form a 16-bit sample, and that there is one sample for each of the NumOfChannels channels.
So, given an array of samples like the one returned by that code,
int[][] samples;
and a byte array for streaming,
byte[] stream;
you might build the converse stream of bytes this way
for (int i=0; i<NumOfSamples; i++) {
for (int j=0; j<NumOfChannels; j++) {
int sample=samples[i][j];
byte low = (byte) (sample & 0xff) ;
byte high = (byte) ((sample & 0xff00 ) >> 8);
stream[((i*NumOfChannels)+j)*2] = low;
stream[(((i*NumOfChannels)+j)*2)+1] = high;
}
}

Fast reading of little endian integers from file

I need to read a binary file consisting of 4 byte integers (little endian) into a 2D array for my Android application. My current solution is the following:
DataInputStream inp = null;
try {
inp = new DataInputStream(new BufferedInputStream(new FileInputStream(procData), 32768));
}
catch (FileNotFoundException e) {
Log.e(TAG, "File not found");
}
int[][] test_data = new int[SIZE_X][SIZE_Y];
byte[] buffer = new byte[4];
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
inp.read(buffer);
byteBuffer = ByteBuffer.wrap(buffer);
test_data[j][SIZE_Y - i - 1] = byteBuffer.order(ByteOrder.LITTLE_ENDIAN).getInt();
}
}
This is pretty slow for a 2k*2k array, it takes about 25 seconds. I can see in the DDMS that the garbage collector is working overtime, so that is probably one reason for the slowness.
There has to be a more efficient way of using the ByteBuffer to read that file into the array, but I'm not seeing it at the moment. Any idea on how to speed this up?
Why not read into a 4-byte buffer and then rearrange the bytes manually? It will look like this:
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
inp.read(buffer);
int nextInt = (buffer[0] & 0xFF) | (buffer[1] & 0xFF) << 8 | (buffer[2] & 0xFF) << 16 | (buffer[3] & 0xFF) << 24;
test_data[j][SIZE_Y - i - 1] = nextInt;
}
}
Of course, it is assumed that read reads all four bytes, but you should check for the situation when it's not. This way you won't create any objects during reading (so no strain on the garbage collector), you don't call anything, you just use bitwise operations.
If you are on a platform that supports memory-mapped files, consider the MappedByteBuffer and friends from java.nio
FileChannel channel = new RandomAccessFile(procData, "r").getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, 4 * SIZE_X * SIZE_Y);
map.order(ByteOrder.LITTLE_ENDIAN);
IntBuffer buffer = map.asIntBuffer();
int[][] test_data = new int[SIZE_X][SIZE_Y];
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
test_data[j][SIZE_Y - i - 1] = buffer.get();
}
}
If you need cross-platform support or your platform lacks memory-mapped buffers, you may still want to avoid performing the conversions yourself using an IntBuffer. Consider dropping the BufferedInputStream, allocating a larger ByteBuffer yourself and obtaining a little-endian IntBuffer view on the data. Then in a loop reset the buffer positions to 0, use DataInputStream.readFully to read the large regions at once into the ByteBuffer, and pull int values out of the IntBuffer.
First of all, your 'inp.read(buffer)' is unsafe, as read contract does not guarantee that it will read all 4 bytes.
That aside, for quick transformation use the algorithm from DataInputStream.readInt
I've adapted for you case of byte array of 4 bytes:
int little2big(byte[ ] b) {
return (b[3]&0xff)<<24)+((b[2]&0xff)<<16)+((b[1]&0xff)<<8)+(b[0]&0xff);
}
I don't think it is necessary to reinvent the wheel and perform the byte reordering for endianness again. This is error prone and there is a reason a class like ByteBuffer exists.
Your code can be optimized in the sense that it wastes objects. When a byte[] is wrapped by a ByteBuffer the buffer adds a view, but the original array remains the same. It does not matter wheather the original array is modified/read from directly or the ByteBuffer instance is used.
Therefore, you only need to initialize one instance of ByteBuffer and also have to set the ByteOrder once.
To start again, just use rewind() to set the counter again to the beginning of the buffer.
I have taken your code and modified it as desribed. Be aware that it does not check for errors if there are not enough bytes in the input left. I would suggest to use inp.readFully, as this will throw EOFException if not enough bytes to fill the buffer are found.
int[][] test_data = new int[SIZE_X][SIZE_Y];
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[4]).order(ByteOrder.LITTLE_ENDIAN);
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
inp.read(byteBuffer.array());
byteBuffer.rewind();
test_data[j][SIZE_Y - i - 1] = byteBuffer.getInt();
}
}

Categories