Reputation: 796
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
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
Reputation: 3486
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