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.
Related
I'm trying to write a function which will check if PNG file is not corrupted. Here I found a function, also provided below, which stores file bytes into its own byte array. I know that the first eight bytes of a PNG file always contain the same decimal values 137 80 78 71 13 10 26 10 (hex: 89 50 4e 47 0d 0a 1a 0a).
When I print the context of the byte array which starts with -1-40-1-3201674707370011007207200-1-370-124022222232235333565555686666681088888810101010101 ... and then convert it to decimal values I don't see the magic number in the beginning. Please, what have I misunderstood? I would like to read the image and compare its header to either decimal or hex values.
public static void main(String[] args)
{
File file = new File("src/resources/dog.png");
readContentIntoByteArray(file);
}
private static byte[] readContentIntoByteArray(File file)
{
FileInputStream fileInputStream = null;
byte[] bFile = new byte[(int) file.length()];
try
{
//convert file into array of bytes
fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
for (int i = 0; i < bFile.length; i++)
{
System.out.print((char) bFile[i]);
}
}
catch (Exception e)
{
e.printStackTrace();
}
return bFile;
}
You are printing the actual bytes as characters to the terminal, not the representation of those bytes in decimal or hex, as #Andreas says.
You can check the header with:
byte[] data = readContentIntoByteArray(file);
byte[] expected = new byte[] {-119, 80, 78, 71, 13, 10, 26, 10};
for (int i = 0; i < expected.length; i++) {
if (expected[i] != data[i]) {
System.out.println("mismatch at " + i);
}
}
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.
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.
while (!bStop) {
byte[] buffer = new byte[256];
if (inputStream.available() > 0) {
inputStream.read(buffer);
int i = 0;
for (i = 0; i < buffer.length && buffer[i] != 0; i++) {
}
final String strInput = new String(buffer, 0, i);
System.out.println(strInput);`
}
The inputstream data is coming in encrypted form in bytes. When i print the data i get funny characters. How can i directly convert the inputstream to hexadecimal in a form of -> 01 2A 03 AA.
Please Help.
try like this
byte[] array = ByteStreams.toByteArray(inputStream);
In Java, is there a library anywhere that will, given a byte sequence (preferable expressed as hex), translate to another byte sequence given an InputStream? For example:
InputStream input = new FileInputStream(new File(...));
OutputStream output = new FileOutputStream(new File(...));
String fromHex = "C3BEAB";
String toHex = "EAF6"
MyMagicLibrary.translate(fromHex, toHex, input, output)
So if the input file (in hex looked like)
00 00 12 18 33 C3 BE AB 00 23 C3 BE AB 00
after translation, the result would be
00 00 12 18 33 EA F6 00 23 EA F6 00
Once I did something like this (for trivially patching exe-files) using regexes. I read the whole input into a byte[] and converted into String using latin1, then did the substitution and converted back. It wasn't efficient but it didn't matter at all. You don't need regexes, simple String.replace would do.
But in your case it can be done quite simply and very efficiently:
int count = 0;
while (true) {
int n = input.read();
if (n == (fromAsByteArray[count] & 255)) {
++count;
if (count==fromAsByteArray.length) { // match found
output.write(toAsByteArray);
count = 0;
}
} else { // mismatch
output.write(fromAsByteArray, 0, count); // flush matching chars so far
count = 0;
if (n == -1) break;
output.write(n);
}
}
}
If u mean that u want to use a class whch translate from hex and to hex
here's two methods I usualluy use, u can put them inside a class and reuse it any where u want
public static String toHex(byte buf[]) {
StringBuffer strbuf = new StringBuffer(buf.length * 2);
int i;
for (i = 0; i < buf.length; i++) {
if (((int) buf[i] & 0xff) < 0x10) {
strbuf.append("0");
}
strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
}
return strbuf.toString();
}
public static byte[] fromHexString(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i + 1), 16));
}
return data;
}
Actually I don't understand each line in the code, but I usually reuse them.
Since your input can have spaces then you first need to scrub your input to remove the spaces. After reading a pair of characters just use Byte.parseByte(twoCharString, 16) then use String.format to convert back to a String.
Doing it byte by byte would most likely be VERY inefficient, though easy to test. Once you get the result you want, you can tweak it by reading and parsing a whole buffer and spitting out more than one resulting byte a time, maybe 16 "byte" characters per line for formatting. It is all up to you at that point.
One way to implement this is to use IOUtils and String replace method.
public static void translate(byte[] fromHex, byte[] toHex, InputStream input, OutputStream output) throws IOException {
IOUtils.write(translate(fromHex, toHex, IOUtils.toByteArray(input)), output);
}
public static byte[] translate(byte[] fromHex, byte[] toHex, byte[] inBytes) throws UnsupportedEncodingException {
String inputText = new String(inBytes, "ISO-8859-1");
String outputText = inputText.replace(new String(fromHex, "ISO-8859-1"), new String(toHex, "ISO-8859-1"));
return outputText.getBytes("ISO-8859-1");
}