[java] Write/Read Binary Data of/to a class

Started by
18 comments, last by Halsafar 18 years, 4 months ago
So with your method above?

I only read/write primitives.

This model can work between C++ and Java?

Edit: Now that I can see how I can impliment each objects toByte. How should I go about writing the byte array to the file?

Okay I figured out how to write to file I believe using FileChannel.


[Edited by - Halsafar on December 1, 2005 9:50:23 PM]
Advertisement
Yes, a FileChannel is even better than ByteArray IO streams because you'll be able to work directly with ByteBuffers, changing that interface to something like:

public interface BinaryPersistent {    /**   * Writes the class members into a ByteBuffer instance   * and orders the buffer for proper endianness   */  ByteBuffer toBytes();  /**   * Reads the class members from the given ByteBuffer instance   * Requires an ordering of endianness before attempting to read   */  void read(ByteBuffer data);}


Hope to have helped,
Son Of Cain
a.k.a javabeats at yahoo.ca
Huge help yes. Rating++.
That is how I had to change the interface to get it to write.

Now, can I read in from file using FileChannel as well right?
If so, I'm sure I can figure it out.
Quote:Original post by Halsafar
Now, can I read in from file using FileChannel as well right?
If so, I'm sure I can figure it out.


Yes, you can. And you'll get a ByteBuffer from it.

I suggest you read a bit of the docs for the API, because depending on the size of your files, you'll want to benefit from some features like MappedByteBuffers. This link has several code tips for NIO.

Son Of Cain

a.k.a javabeats at yahoo.ca
Okay I believe you've left me with enough information to accomplish the task.
Particularly that site you gave in your last post.

However, all the examples I'm looking at, including the read/write to bytebuffer via FileChannel examples all allocate the ByteBuffer to be 1024 bytes, enough for 256x4 byte variables. Is there a reason for this? Or could I very well allocate however much space I know I'll need (powers of 2)?
Okay I've almost got it.
Except the bytes are coming out proper.

I'll post the code, the expected output, the real output:
Nice to note, the code is a bit messy, cuz I'm messin around with trying to get this to work.


import java.nio.*;import java.nio.channels.*;import java.io.*;public class test{    public interface BinaryPersistent {	   	   abstract public ByteBuffer toBytes();	   	   abstract void read(ByteBuffer data);	       }    private static  class A implements BinaryPersistent    {	   int i = 10;	   public A()	   {		  System.out.println("Hello from A");	   }  	   public ByteBuffer toBytes() {		  //Fill some info		  ByteBuffer buf = ByteBuffer.allocate(1024);		  buf.putInt(50); // use setters to write data		  buf.putInt(50); // use setters to write data		  buf.putInt(50); // use setters to write data		  buf.putInt(50); // use setters to write data		  buf.putInt(50); // use setters to write data		  buf.putInt(50); // use setters to write data		  buf.putInt(50); // use setters to write data		  buf.rewind();		  // order buffer		  System.out.println("Converted A to Bytes");		  return buf;	   }	   public void read(ByteBuffer buffer) {		  // get data using getXXX() methods on the buffer;	   }    }    private static final class B extends A    {	   int j = 20;	   public B()	   {		  System.out.println("Hello from B");	   }    }    public static void main(String[] Args)    {	   B b1 = new B();	   File file = new File("filename");	   	   ByteBuffer bbuf = b1.toBytes();	   boolean append = false;    	   try		  {			 // Create a writable file channel			 FileChannel wChannel = new FileOutputStream(file, append).getChannel();			 			 // Write the ByteBuffer contents; the bytes between the ByteBuffer's			 // position and the limit is written to the file			 wChannel.write(bbuf);			 			 // Close the file			 wChannel.close();		  } 	   catch (IOException e) 		  {		  } 	   try 		  {			 // Obtain a channel			 ReadableByteChannel channel = new FileInputStream("filename").getChannel();    			 // Create a direct ByteBuffer; see also e158 Creating a ByteBuffer			 ByteBuffer buf = ByteBuffer.allocateDirect(10);    			 int numRead = 0;			 while (numRead >= 0) {				// read() places read bytes at the buffer's position so the				// position should always be properly set before calling read()				// This method sets the position to 0				buf.rewind();    				// Read bytes from the channel				numRead = channel.read(buf);    				// The read() method also moves the position so in order to				// read the new bytes, the buffer's position must be set back to 0				buf.rewind();    				// Read bytes from ByteBuffer; see also				// e159 Getting Bytes from a ByteBuffer				for (int i=0; i < numRead / 4; i++) {				    System.out.println(buf.getInt());				    //byte b = buf.get();				 }			 }			 		  }	   catch (Exception e)		  {		  }    }}



Expected output:
50
50
50
50
50
50
50
0
0
0
0
... (0's for the rest of the btyes)

Actual Output:
50
50
3276800
3276800
50
50
0
0
0
0
.... (the rest is 0's)






Edit: Okay, I shoulda looked over it more. The bytebuffer was only being allocated to 10. So I'm sure I was just overlapping the bytes or something...

[Edited by - Halsafar on December 2, 2005 3:03:34 PM]
Yeah dude, just that ;)

Remember to order the buffer using the correct endianness! Otherwise, you won't be able to use it on the C++ side.

Son Of Cain
a.k.a javabeats at yahoo.ca
Yes, that was my next step of business.

Okay so I able to write an int with java and read it with C++. That works fine.

Now my problem is, Java cannot read it back.
I am telling the ByteBuffer in the read part of my snippet to use BIG_ENDIAN. However, thats not working. I believe the ReadableByteChannel gets the bits as they are (LITTLE_ENDIAN) and then it doesn't matter what order the byte buffer is in...

I am always getting the hex opposite of 50, so obviously its coming out of the file in the wrong order.
0x00000032
vs
0x32000000


As soon as I allocate the bytebuffer I call the order() method.
Maybe you can point something out?

I figure a solution would be to try and read the bytes in backwards somehow...
Quote:Original post by Halsafar
As soon as I allocate the bytebuffer I call the order() method.
Maybe you can point something out?


Are you ordering the ByteBuffer instance AFTER you read data into it? That's how it must be done. If that is not working, then I have no idea what it might be... weird.

If all else fails... is there a way to change the endianness of a binary file in C++? (I'm sure there must be something)

Son Of Cain
a.k.a javabeats at yahoo.ca
Actually. LoL
I just figured it out.

See for Java to read/write a binary which C++ can read/write:

- write as little endian
- read as little endian


I was telling java to write as LITTLE read it as BIG. I have to tell Java to read/write as LITTLE, since the file is in LITTLE.

All fixed. All working.
Thanks a ton for your help.

This topic is closed to new replies.

Advertisement