I have this code to compress float values, but the size of the output is bigger than the original.
Mi goal is save the compressed data (byte array) in a file, then inflate the data to get the original float value.
What am I doing wrong?
public void floatToArrayByte() throws IOException {
float f = 3574.34568f;
byte arayByte[] = ByteBuffer.allocate(4).putFloat(f).array();
System.out.println("Original values");
for (int i = 0; i < arayByte.length; i++) {
System.out.print(arayByte[i]);
System.out.print(" ");
}
System.out.println("");
arayByte = this.compress(arayByte);
System.out.println("Compress values");
for (int i = 0; i < arayByte.length; i++) {
System.out.print(arayByte[i]);
System.out.print(" ");
}
System.out.println("");
}
public byte[] compress(byte[] data) throws IOException {
Deflater deflater = new Deflater();
deflater.setInput(data);
deflater.setLevel(Deflater.DEFLATED);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
deflater.finish();
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
byte[] output = outputStream.toByteArray();
System.out.println("Original size: " + data.length + " Bytes");
System.out.println("Compressed size: " + output.length + " Bytes");
return output;
}
This is what I get
Original values
69 95 101 -120
Original size: 4 Bytes
Compressed size: 12 Bytes
Compress values
120 -38 115 -115 79 -19 0 0 3 -121 1 -110
For very short inputs (like just 4 bytes in your case) you will always get a 'compressed' value longer than the input, because the compressed stream contains some headers.
Try to compress more data (like 100 thousand floats) to see the difference.
Related
I am comparing File.length() with counting bytes and I always get 1 byte more with File.length().
Here is the snippet i am using to compare:
File testFile = new File("testdir", "testfile.txt");
FileInputStream in = new FileInputStream(testFile );
byte[] buffer = new byte[1024];
int len = in.read(buffer);
int byteCount = len;
while (len != -1) {
len = in.read(buffer);
byteCount += len;
}
System.out.println("count: " + byteCount + ", file.length(): " +
testFile.length() + ", is_equal: "+(byteCount == testFile.length()));
and the output is count: 15853294, file.length(): 15853295, is_equal: false
Where does 1 byte come from? is it EOF?
The last read operation returns -1 and you are adding this to byteCount.
I have problem with reading understood data, when I used Parsing (char) the numbers became strange char in ASCII, here is the code :
static void doTestByteFiles() throws IOException {
File file = new File("sample1.data");
FileOutputStream outStream = new FileOutputStream(file); //Warning!!!!
byte[] outByteArray = {10,20,30,40,50,60,70,80,(byte)'J',(byte)'a',(byte)'v',(byte)'a'};
outStream.write(outByteArray);
outStream.close();
FileInputStream inStream = new FileInputStream(file);
int fileSize = (int) file.length();
byte[] inByteArray = new byte[fileSize];
inStream.read(inByteArray);
for (int i = 0; i < fileSize; i++) {
System.out.println((char) inByteArray[i]);
}
inStream.close();
}
the result:
(
2
<
F
P
J
a
v
a
result I expect :
10
20
30
40
50
60
70
80
J
a
v
a
I tried to use (byte) instead (char), same problem but the Java word became numbers in ASCII , Any help please ?
The numbers in the byte[] array are interpreted as byte values. You have to write Intergers and convert them to byte inside the array.
This question already has answers here:
Removing the first 16 bytes from a byte array
(4 answers)
Closed 3 years ago.
I have a byte array named byteArr[].I need to remove first 4 bytes from it.My code is shown below. Here I use the byte array to store the input string.I got some unwanted byte with the output i.e the first four bytes is not needed from the fifth onwards is correct. My program is to take id from respected rfid tag using an rfid machine.
public class Serverc {
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static void connection() throws IOException {
ServerSocket ss = new ServerSocket(9888);//exce
ss.setSoTimeout(300000000);//exce
System.out.println("Waiting for client on port " + ss.getLocalPort() + "...");
while (true) {
Socket server = ss.accept();//exce
System.out.println("Just connected to " + server.getRemoteSocketAddress());
int available = 0;
DataInputStream in = new DataInputStream(server.getInputStream());//exce
int input = 0;
//BufferedReader br = new BufferedReader(in);
byte byteArr[] = new byte[28];
try {
//read till the end of stream
//while((input = in.available()) != -1)
while ((input = in.read(byteArr)) != -1) {
System.out.println("Size read is " + input);
System.out.println("Data is " + bytesToHex(byteArr));
}
//System.out.println("inside finally");
server.close();//exce
//System.out.println("outside finally");
} catch (SocketTimeoutException ex) {
System.out.println("Socket timed out!");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]) throws IOException {
Serverc obj = new Serverc();
obj.connection();
}
}
Here is my console
Waiting for client on port 9888...
Just connected to /106.208.71.50:61532
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Size read is 28
Data is 55000016910001DB00FB63ABEEAFC1EC888F10263410050711148F3500000000
Here I need to remove 55000016 from the output.
Advance thanks
You could use Arrays.copyOfRange method to filter the unwanted bytes and save the result to a new byte array.
byte[] filteredByteArray = Arrays.copyOfRange(byteArr, 4, byteArr.length);
If you want to skip the first four bytes change this,
for (int j = 0; j < bytes.length; j++) {
to something like
for (int j = 4; j < bytes.length; j++) {
Or you might use String.substring(int)
bytesToHex(byteArr).substring(8); // <-- skip the first 4 bytes
You have a larger problem than skipping the 4 bytes at the start of each of your packets. Your code does this:
byte byteArr[] = new byte[28];
try {
while ((input = in.read(byteArr)) != -1) {
System.out.println("Size read is " + input);
System.out.println("Data is " + bytesToHex(byteArr));
}
(commented-out lines removed)
Note that you cannot guarantee that all 28 bytes will be read on each call to in.read(), but that your bytesToHex() method is assuming that 28 valid bytes are present in the array. You need to collect data that you read into the array until you have all of your packet before processing it, probably using a DataInputStream with the method readFully(byte[]). Then you can skip the first 4 bytes as suggested in the other answers.
It is best for you to skip the 4 bytes. But if you want to remove them, you should use this solution (your array may become massive). This algorithm is best you can get in Java for your problem. O(1) space , O(n) time.
void removeFourBytes(byte[] a) {
for (int i = 4; i < a.length; i++) {
a[i-4]=a[i];
}
for (int i = a.length - 1; i > a.length - 5; i--) {
a[i] = 0;
}
}
Second best option would be System.arrayCopy() - O(n) space, O(n) time.
It might be a question already asked, but I have not found a satisfactory answer yet out there. In particular because this conversion has always been done in c or C++.
Btw, how do you convert an hexadecimal file (200MB) into its UINT32 Big-endian representation in Java?
This an example of what I am trying to achieve:
54 00 00 00 -> 84
55 F1 2E 04 -> 70185301
A2 3F 32 01 -> 20070306
and so on
EDIT
File fileInputString = new File(inputFileField.getText());
FileInputStream fin = new FileInputStream(fileInputString);
FileOutputStream out = new FileOutputStream(fileDirectoryFolder.getText() +"/"+ fileInputString.getName());
byte[] fileContent = new byte[(int)fileInputString.length()];
fin.read(fileContent);
System.out.println("File Lenght" + fileContent.length);
for(int i = 0; i < fileContent.length; i++){
Byte b = fileContent[i]; // Boxing conversion converts `byte` to `Byte`
int value = b.intValue();
out.write(value);
}
close();
System.out.println("Done");
EDIT 2
File fileInputString = new File(inputFileField.getText());
FileInputStream fin = new FileInputStream(fileInputString);
FileOutputStream out = new FileOutputStream(fileDirectoryFolder.getText() +"/"+ fileInputString.getName());
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] fileContent = new byte[(int)fileInputString.length()];
System.out.println("File Lenght" + fileContent.length);
int bytesRead;
while (( bytesRead = fin.read(fileContent)) != -1) {
ByteBuffer.wrap(fileContent).order(ByteOrder.LITTLE_ENDIAN).getLong();
bos.write(fileContent, 0, bytesRead);
}
out.write(bos.toByteArray());
System.out.println("Done");
EDIT 3
DataOutputStream out = new DataOutputStream(new FileOutputStream(output));
DataInputStream in = new DataInputStream(new FileInputStream(input))) {
int count = 0;
while (count < input.length() - 4) {
in.readFully(buffer, 4, 4);
String s=Long.toString(ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).getLong());
out.writeBytes( s + " ");
count += 4;
}
Thanks
The following code should hopefully suffice. It uses long values to ensure we can fully represent the range of positive values that four bytes can represent.
Note: this code assumes the hex input is four bytes. You may want to add some more checks and measures in production code.
private static long toLong(String hex) {
hex = hex.replace(" ", "") + "00000000";
byte[] data = DatatypeConverter.parseHexBinary(hex);
return ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).getLong();
}
public static void main(String[] args) throws Exception {
System.out.println(toLong("54 00 00 00"));
System.out.println(toLong("55 F1 2E 04"));
System.out.println(toLong("A2 3F 32 01"));
System.out.println(toLong("FF FF FF FF"));
}
Output:
84
70185301
20070306
4294967295
Based on your recent edits, I propose some code such as the following. Note that it assumes your input is a multiple of four bytes in length. Any left-over bytes are ignored:
File input = new File("whatever");
byte[] buffer = new byte[8];
List<Long> result = new ArrayList<>();
try (DataInputStream in = new DataInputStream(new FileInputStream(input))) {
int count = 0;
// Note: any trailing bytes are ignored
while (count < input.length() - 4) {
in.readFully(buffer, 4, 4);
result.add(ByteBuffer.wrap(buffer)
.order(ByteOrder.LITTLE_ENDIAN).getLong());
count += 4;
}
}
You need to switch the byte order within the 4 bytes that form an int. The conversion is symetric, so when the input is little endian, output becomes big endian and vice versa.
Big Endian: 12 34 56 78
Little Endian: 78 56 34 12
So if you were doing that while processing an InputStream, read four bytes, and write them to output in reverse order.
I am developing an application which I capture videos in it. I am saving the recorded videos to the phone. What I want to do is to convert the saved files to byte arrays.
// Serialize to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos);
out.writeObject(yourObject);
out.close();
// Get the bytes of the serialized object
byte[] buf = bos.toByteArray();
//write bytes to private storage on filesystem
FileOutputStream fos = new FileOutPutStream("/....your path...");
fos.write(buf);
fos.close();
You can use this code which may help you:
public static byte[] getBytesFromFile(File file) throws IOException {
InputStream is = new FileInputStream(file);
System.out.println("\nDEBUG: FileInputStream is " + file);
// Get the size of the file
long length = file.length();
System.out.println("DEBUG: Length of " + file + " is " + length + "\n");
/*
* You cannot create an array using a long type. It needs to be an int
* type. Before converting to an int type, check to ensure that file is
* not loarger than Integer.MAX_VALUE;
*/
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large to process");
return null;
}
// Create the byte array to hold the data
byte[] bytes = new byte[(int)length];
// Read in the bytes
int offset = 0;
int numRead = 0;
while ((offset < bytes.length) && ((numRead=is.read(bytes, offset, bytes.length-offset)) >= 0)) {
offset += numRead;
}
// Ensure all the bytes have been read in
if (offset < bytes.length) {
throw new IOException("Could not completely read file " + file.getName());
}
is.close();
return bytes;}