user1423893
user1423893

Reputation: 796

Writing binary file in C# and then reading the same file in C++

I am writing a binary file in C# using the BinaryWriter class

using (var b = new System.IO.BinaryWriter(System.IO.File.Open("C:\\TextureAtlas0.txa", 
       System.IO.FileMode.Create)))
{
  int count;

  // Write the number of source rectangle entries
  count = textureAtlas.Rectangles.Count;

  b.Write(count);

  for (int i = 0; i < count; ++i)
  {
    b.Write(textureAtlas.SpriteNames[i]);
    b.Write(textureAtlas.Rectangles[i].X);
    b.Write(textureAtlas.Rectangles[i].Y);
    b.Write(textureAtlas.Rectangles[i].Width);
    b.Write(textureAtlas.Rectangles[i].Height);
  }
}

I then try and read the same file into C++ using the following steps.

I have a struct that holds the data in the same order it was written.

struct TextureAtlasEntry 
{
    std::string name;
    int x;
    int y;
    int width;
    int height;
};

The count is read first

int count;

fread(&count, sizeof(int), 1, LoadFile);

I then attempt to use the count value to determine the list size that will hold the data. I can't seem to use an array as the value for count will be different depending on the file that is read.

std::list<TextureAtlasEntry> entries;
fread(&entries, sizeof(TextureAtlasEntry), count, LoadFile);

fclose(LoadFile);

The code above does not work. I can get the count to be read correctly but the memcpy command causes an access violation with fread and the entries list.

How can I read the data correctly and should I swap fread with a C++ equivalent?

EDIT:

I can now read the entire binary file into memory using the following code

ifstream::pos_type size;
char *memblock;

ifstream file ("TextureAtlas0.txa", ios::in|ios::binary|ios::ate);

if (file.is_open())
{
    size = file.tellg();
    memblock = new char[size];
    file.seekg (0, ios::beg);
    file.read (memblock, size);
    file.close();

    printf("File content is in memory");

    delete[] memblock;
}
else 
{
    printf("Unable to open file");
}

Now the file is in memory, how do I convert the char[] data into struct data?

Upvotes: 2

Views: 3253

Answers (2)

AndrewR
AndrewR

Reputation: 6748

According to the documentation, BinaryWriter(String) writes...

A length-prefixed string represents the string length by prefixing to the string a single byte or word that contains the length of that string. This method first writes the length of the string as a UTF-7 encoded unsigned integer, and then writes that many characters to the stream by using the BinaryWriter instance's current encoding.

In your C++ code, you are just trying to read in a number of bytes the size of your struct, which is a different format than BinaryWriter uses.

Are you using .NET for the C++ code? If so, just use the BinaryReader class to read in the file instead.

If not, you'll have to split up the read a little bit. When you are ready to read the name, you'll first have to read a "UTF-7 encoded unsigned integer", then read that many more bytes to get the string.

EDIT

Based on your comment below, it seems you will not be using C++.NET, so I think you have two options. 1) Write out the data in C# in a way you will be able to read it into C++ (using fixed-length strings) 2) Figure out the way BinaryWriter.Write() writes the data so you can read it properly in C++.

Pseudocode - I think it's something like this. Like I said in a comment below, my C++ is rusty, but this is basic algorithm should be close.

read from file int num - number of items
for (i=0;i<num;i++){
   read int stringBytes - size of string
   read string stringBytes bytes - the name
   read int X4
   create your struct and add to list/array/dictionary
}

Upvotes: 2

Rather than a string data type problem explained in another answer, here is one more thing. std::list is a doubly linked list which contains extra pointers by nature, so direct fread/memcpy probably doesn't give you what you have stored in c# snippet.

Upvotes: 0

Related Questions