4

For example in C I have structure:

typedef struct {
    int number;
    double x1;
    double y1;
    double x2;
    double y2;
    double x3;
    double y3;
} CTRstruct;`

Then I write it to file fwrite(&tr, 1, sizeof(tr), fp); (tr - its CTRstruct var, fp - File pointer);

Then I need to read it with Java! I really don't know how to read struct from file... I tried to read it with ObjectInputStream(), last idea is to read with RandomAccessFile() but I also don't know how to... (readLong(), readDouble() also doesn't work, it works ofcource but doesn't read correct data). So, any idea how to read C struct from binary file with Java?


If it's interesting, my version to read integer (but it's ugly, & I don't know what to do with double):

public class MyDataInputStream extends DataInputStream{

public MyDataInputStream(InputStream AIs) {
    super(AIs);
}

public int readInt1() throws IOException{
    int ch1 = in.read();
    int ch2 = in.read();
    int ch3 = in.read();
    int ch4 = in.read();
    if ((ch1 | ch2 | ch3 | ch4) < 0)
        throw new EOFException();
    return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0));
}

with double we can deal the same way (like with int or with long (8bytes) & then convert to double with native func).

DaunnC
  • 1,301
  • 15
  • 30
  • 1
    The way you write the struct to file is wrong, take a look at this: http://stackoverflow.com/questions/10153155/write-raw-struct-contents-bytes-to-a-file-in-c-confused-about-actual-size-wri – Vincenzo Pii Apr 15 '12 at 14:32
  • 4
    The actually correct answer would be to not dump the memory representation of the struct to a file like this. – celtschk Apr 15 '12 at 14:34
  • yes, mb it's silly to do like this, but i need to do it.. (I mean to write in file the hole struct) – DaunnC Apr 15 '12 at 14:37
  • 2
    You did open the file as binary? I.e. `fp = fopen("some/file", "wb");`? Then you have to watch out for things like padding and how Java handle [endianess](http://en.wikipedia.org/wiki/Endianess) for the integer, and if `double` is the same format. – Some programmer dude Apr 15 '12 at 14:38
  • @DaunnC: *Why* do you think you need to do it like this? – celtschk Apr 15 '12 at 14:43
  • 2
    @Daunn Well since no answer will be capable of providing the "correct" answer in all cases, the simplest solution would be to just read all zeros. Sure that's almost always wrong - but that's at least better than being wrong only every 100th time. Makes debugging *much* simpler – Voo Apr 15 '12 at 14:47
  • @DaunnC, you can write all the fields of the struct one at a time without just dumping the memory representation, and that's the only way to do it in a way that's guaranteed to be compatible with Java. – Louis Wasserman Apr 15 '12 at 14:56
  • thx alot to every one! your information was really helpful. If it is interesting how i dealed with trouble - see first (my) post. – DaunnC Apr 15 '12 at 17:19

6 Answers6

5

You should not use fwrite of the entire struct, because you will inevitably run into issues with padding and endian-ness. The C side will dump the entire struct the way it is in the memory, with all its gaps that the compiler puts in for performance etc. That's "the mother of non-portability"!

Instead, you should use protocol buffers, JSON, or some other mean of portable serialization to accomplish your task.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
4

Use a library that serializes your data to disk. That will make reading it back into Java a whole lot easier. Make sure that the library uses a well-documented storage format.

Community
  • 1
  • 1
nes1983
  • 15,209
  • 4
  • 44
  • 64
2

You have to find out what size those C types (int, double) and which endianness (thanks andrew cooke) are used in the architecture you executed the program in and use same sized types in Java.

m0skit0
  • 25,268
  • 11
  • 79
  • 127
1

DataInputStream is the typical way to read primitive inputs in Java -- I think you ought to be able to do

int number = dataInputStream.readInt();
double x1 = dataInputStream.readDouble();
...
double y3 = dataInputStream.readDouble();

but I'm not 100% sure that endianness and other issues will be compatible.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • 2
    I would expect that the padding between the `int` and the first `double` needs to be handled. – Daniel Fischer Apr 15 '12 at 14:34
  • 3
    It's really totally dependent on how C decides to represent it in memory; it'd be best to actually do that one field at a time, properly, rather than just dumping the in-memory representation. – Louis Wasserman Apr 15 '12 at 14:37
  • 1
    Well the first question is: Is the int 4 or 8 byte? If it's 4 byte we probably have to use padding, if not it fits fine, but suddenly we can't use a java int anymore but need a long. And so on and so on. It's just a really bad idea. – Voo Apr 15 '12 at 14:49
  • int 4 byte, it seems to me, cause these methods work incorrect – DaunnC Apr 15 '12 at 14:55
1

Well, in the unlikely event that JNI is an option for you, you could read it back in C. Using swig you could easily expose your struct, along with its function to read from the file. Of course all the hassle that comes with JNI isn't worth for this problem alone, but you might already be using it.

enobayram
  • 4,650
  • 23
  • 36
0

I use http://javolution.org/ (or https://github.com/javolution/javolution) . Even if the project seems 'dead', I didn't find anything as simple and efficient that it for "Struct".

Have a look here to know how to create a Class that map the buffer: Struct Javadoc

iriiko
  • 43
  • 4