I have the following piece of code in C++
int magic;
stream.read(&magic, sizeof(magic));
Which stores the value of magic from an array of bytes.
I want to migrate it to Java, so far I have this:
int magic = stream[0];
But it is not working. I think that it is due to the length of the ints in Java and C++. Shall I use two bytes in the Java part to retrieve the proper magic number?
byte[] stream = ...
ByteBuffer buf = ByteBuffer.wrap(stream);
buf.order(ByteOrder.LITTLE_ENDIAN);
int magic = buf.readInt();
See ByteBuffer. A java int is always 4 bytes signed, and per default java uses a BIG_ENDIAN byte order, so you might want to set a reversed order.
Related
This question already has answers here:
Difference between int[] array and int array[]
(26 answers)
Closed 7 years ago.
I'm currently trying to get my head around a piece of code that I found. Firstly, I'm not sure why the code appears like:
byte z[] = new byte[5];
instead of:
byte[] z = new byte[5];
I mean, is byte z[] not there to declare an array of bytes? Or is this code doing something else?
Secondly, why would someone choose bytes over doubles or ints. It seems that a byte is any number from -128 to 127. What's the point in choosing that over a double?
byte[] z is equivalent to byte z[] are just two different methods of represent the same.
Note that the java code conventions of sun (before becoming Oracle) propose to use the first over the second. So it preferreable to use
byte[] z = new byte[5];
instead of
byte z[] = new byte[5];
For the second part of your question.
byte uses 1 byte
char uses 2 bytes
int uses 4 bytes
long uses 8 bytes
So the best is to use the smallest numeric type to avoid memory occupancy.
For the array declaration: Java supports c-style array declaration aswell as it's own way that is usually used. byte[] z is equivalent to byte z[]. byte takes less memory than double and int and provides better performance than bigger datatypes (especially better than double).
I apologies if the title of this question is not clear, but i cannot figure out the best way to describe my predicament in so few words.
I am writing a communication framework between java and C# using sockets and byte by byte transfer of information.
I have ran into an issue which has been confusing me for a good few hours now. As you hopefully know. java's byte base type is signed, meaning it can store -128 to +127 if you were to represent it in integer form. C# however, uses unsigned bytes, meaning that it store 0-255 in integer form.
This is where i am encountering the issue. If need to send some bytes of information from my c# client to my java server, i use the following code:
C#:
MemoryStream stream;
public void write(byte[] b, int off, int len) {
stream.Write(b, off, len);
}
Java:
DataInputStream in;
public int read(byte[] b, int off, int len) throws IOException{
in.read(b, off, len));
}
As you can see these are very very similar pieces of code that when used within their own languages will produce predictable results. However, due to the differences in the signing these will produce unusable data.
I.e if i send 255 from my c# client to java server, I will receive a value of -1 on the java server. This is because both of those values are represented of these 8 bits: 11111111
Preferably in order to solve this problem I would need to use the following code, using sbyte, c#'s signed byte.
C#:
MemoryStream stream;
public void write(sbyte[] b, int off, int len) {
//Code to change sbyte into a byte but keeping it in the form in which java will understand
stream.Write(b, off, len);
}
I basically need to store java's representation of a signed byte inside an unsigned C# byte in order to send that byte across to the server. I will also need to do this in reverse to get an sbyte out of a byte received from my java server.
I have tried numerous ways in which to do this with no success. If anyone has any idea as to how i can go about this i would be GREATLY appreciative.
You basically don't need to do anything except stop thinking about bytes as numbers. Think of them as 8 bits, and Java and C# are identical. It's rare that you really want to consider a byte as a magnitude - it's usually just binary data like an image, or perhaps encoded text.
If you want to send the byte 10100011 across from Java to C# or vice versa, just do it in the most natural way. The bits will be correct, even if the byte values will be different when you treat them as numbers.
It's not entirely clear what data you're actually trying to propagate, but in 99.9% of cases you can just treat the byte[] as opaque binary data, and transmit it without worrying.
If you do need to treat the bytes as magnitudes, you need to work out which range you want. It's easier to handle the Java range, as C# can support it with sbyte[]... but if you want the range 0-255, you just need to convert the byte to an int on the Java side and mask it with the bottom 8 bits:
byte b = ...;
int unsigned = b & 0xff;
If you really need to treat byte[] as sbyte[] or vice versa on C#, you can use a little secret: even though C# doesn't allow you to convert between the two, the CLR does. All you need to do is go via a conversion of the reference to object to fool the C# compiler into thinking it might be valid - otherwise it thinks it knows best. So this executes with no exceptions:
byte[] x = new byte[] { 255 };
sbyte[] y = (sbyte[]) (object) x;
Console.WriteLine(y[0]); // -1
You can convert in the other direction in exactly the same way.
I just found there is no readUnsignedInt() method in the RandomAccessFile class. Why? Is there any workaround to read an unsigned int out from the file?
Edit:
I want to read an unsigned int from file and put it into a long space.
Edit2:
Cannot use readLong(). it will read 8 bytes not 4 bytes. the data in the file have unsigned ints in 4 bytes range.
Edit3:
Found answer here: http://www.petefreitag.com/item/183.cfm
Edit4:
how about if the data file is little-endian? we need to bits swap first?
I'd do it like this:
long l = file.readInt() & 0xFFFFFFFFL;
The bit operation is necessary because the upcast will extend a negative sign.
Concerning the endianness. To the best of my knowledge all I/O in Java is done in big endian fashion. Of course, often it doesn't matter (byte arrays, UTF-8 encoding, etc. are not affected by endianness) but many methods of DataInput are. If your number is stored in little endian, you have to convert it yourself. The only facility in standard Java I know of that allows configuration of endianness is ByteBuffer via the order() method but then you open the gate to NIO and I don't have a lot of experience with that.
Edited to remove readLong():
You could use readFully(byte[] b, int off, int len) and then convert to Long with the methods here: How to convert a byte array to its numeric value (Java)?
Because there is no unsigned int type in java?
Why not readLong() ?
You can readLong and then take first 32 bits.
Edit
You can try
long value = Long.parseLong(Integer.toHexString(file.readInt()), 16);
Depending on what you are doing with the int, you may not need to turn it into a long. You just need to be aware of the operations you are performing. After all its just 32-bits and you can treat it as signed or unsigned as you wish.
If you want to play with the ByteOrder, the simplest thing to do may be to use ByteBuffer which allows you to set a byte order. If your file is less than 2 GB, you can map the entire file into memory and access the ByteBuffer randomly.
How can I read a file to bytes in Java?
It is important to note that all the bytes need to be positive, i.e. the negative range cannot be used.
Can this be done in Java, and if yes, how?
I need to be able to multiply the contents of a file by a constant. I was assuming that I can read the bytes into a BigInteger and then multiply, however since some of the bytes are negative I am ending up with 12 13 15 -12 etc and get stuck.
Well, Java doesn't have the concept of unsigned bytes... the byte type is always signed, with values from -128 to 127 inclusive. However, this will interoperate just fine with other systems which have worked with unsigned values for example, C# code writing a byte of "255" will produce a file where the same value is read as "-1" in Java. Just be careful, and you'll be okay.
EDIT: You can convert the signed byte to an int with the unsigned value very easily using a bitmask. For example:
byte b = -1; // Imagine this was read from the file
int i = b & 0xff;
System.out.println(i); // 255
Do all your arithmetic using int, and then cast back to byte when you need to write it out again.
You generally read binary data from from files using FileInputStream or possibly FileChannel.
It's hard to know what else you're looking for at the moment... if you can give more details in your question, we may be able to help you more.
With the unsigned API in Java 8 you have Byte.toUnsignedInt. That'll be a lot cleaner than manually casting and masking out.
To convert the int back to byte after messing with it of course you just need a cast (byte)value
You wrote in a comment (please put such informations in the question - there is an edit link for this):
I need to be able to multiply the contents of a file by a constant.
I was assuming that I can read the bytes into a BigInteger and then
multiply, however since some of the bytes are negative I am ending
up with 12 13 15 -12 etc and gets stuck.
If you want to use the whole file as a BigInteger, read it in a byte[], and give this array (as a whole) to the BigInteger-constructor.
/**
* reads a file and converts the content to a BigInteger.
* #param f the file name. The content is interpreted as
* big-endian base-256 number.
* #param signed if true, interpret the file's content as two's complement
* representation of a signed number.
* if false, interpret the file's content as a unsigned
* (nonnegative) number.
*/
public static BigInteger fileToBigInteger(File f, boolean signed)
throws IOException
{
byte[] array = new byte[file.length()];
InputStream in = new FileInputStream(file);
int i = 0; int r;
while((r = in.read(array, i, array.length - i) > 0) {
i = i + r;
}
in.close();
if(signed) {
return new BigInteger(array);
}
else {
return new BigInteger(1, array);
}
}
Then you can multiply your BigInteger and save the result in a new file (using the toByteArray() method).
Of course, this very depends on the format of your file - my method assumes the file contains the result of the toByteArray() method, not some other format. If you have some other format, please add information about this to your question.
"I need to be able to multiply the contents of a file by a constant." seems quite a dubious goal - what do you really want to do?
If using a larger integer type internally is not a problem, just go with the easy solution, and add 128 to all integers before multiplying them. Instead of -128 to 127, you get 0 to 255. Addition is not difficult ;)
Also, remember that the arithmetic and bitwise operators in Java only returns integers, so:
byte a = 0;
byte b = 1;
byte c = a | b;
would give a compile time error since a | b returns an integer. You would have to to
byte c = (byte) a | b;
So I would suggest just adding 128 to all your numbers before you multiply them.
Some testing revealed that this returns the unsigned byte values in [0…255] range one by one from the file:
Reader bytestream = new BufferedReader(new InputStreamReader(
new FileInputStream(inputFileName), "ISO-8859-1"));
int unsignedByte;
while((unsignedByte = bytestream.read()) != -1){
// do work
}
It seems to be work for all bytes in the range, including those that no characters are defined for in ISO 8859-1.
How would one go about doing this? Also, is there an easy way to do it? Using a lib like Boost or something?
The DataOutputStream which writes out the int writes out a 4 byte int, with the high bytes first. Read into char*, reinterpret and if you need to convert the byte order use ntohl.
ifstream is;
is.open ("test.txt", ios::binary );
char* pBuffer = new char[4];
is.read (pBuffer, 4);
is.close();
int* pInt = reinterpret_cast<int*>(pBuffer);
int myInt = ntohl(*pInt); // This is only required if you are on a little endian box
delete [] pBuffer;
The only cross-platform way to do it is to read it byte by byte (that is, char by char), and build an integer out of them. You'd want to use long, because int is not guaranteed to be wide enough to hold a 32-bit value. I'll assume you've read the bytes into a char[4] array here (other answers have already demonstrated how to do that):
char bytes[4];
...
long n = (long(bytes[0]) << 24) | (long(bytes[1]) << 16) |
(long(bytes[2]) << 8) | long(bytes[3])
Ideas:
Read it in as straight binary, then convert/interpret bytes as necessary. So if Java wrote out 4 bytes for the int, then you read in 4 bytes. If there is any endian-ness to change then do that, then cast (or copy) the byte array to a c++ int
If you can change the Java code, you could write it out as something common that C++ can read like UTF-8 text or ascii, or Google Protocol Buffers format or something else.