We help IT Professionals succeed at work.

Write to binary File,struct with AnsiString.

Medium Priority
Last Modified: 2013-11-17
Hello everyone.
I am trying to write to a file a struct of the following type:

typedef struct ResFileStr_
 AnsiString ImagePath;
 int RecognitionMethod;
 int Background,ThresholdMethod;
 float Recall,Precission;

So i create the file with fp=fopen("test.res",wb") and then i write a struct with fwrite(&rec,sizeof rec,1,fp).
The rec struct data is something like this:rec.ImagePath="C:\\di1\\dir2\\file.jpg" rec.RecognitionMethod=2 and so on.
Then when i try to open it and read it all fields are the way they should be except the ImagePath field.
I fp=fopen("test.res","rb") and i fread(&rec,sizeof rec,1,fp) and rec.imagePath=@#^saa//566\\\5656^^$%233..."something like this.Any ideas.
Thanks In Advance.
Sotiris Zegiannis,Greece,TUOA,Computer Science Department.

Watch Question

Before i post my oppinion about the way I THINK its better:
Open the file you saved with a hex editor.
Check out if the bytes of the field is valid.
Maybe there is something wrong there.
That's for starters.

You are using the "c" way...
It will be better to use the C++ Builder way as explained at online help...

But check out first the file and we will discuss again...

George Tokas.


I have already used the c++ way,if that's what you mean,by using the ifstream/ofstream classes,but the problem remains.Moreover the files are ok as far as validation is concerned.
>>I have already used the c++ way,if that's what you mean,by using the ifstream/ofstream classes
No I don't mean that...
I mean:
void __fastcall TForm1::Button1Click(TObject *Sender)

  int iFileHandle;
  int iFileLength;
  int iBytesRead;
  char *pszBuffer;
  if (OpenDialog1->Execute())
      iFileHandle = FileOpen(OpenDialog1->FileName, fmOpenRead);
      iFileLength = FileSeek(iFileHandle,0,2);
      pszBuffer = newchar[iFileLength+1];
      iBytesRead = FileRead(iFileHandle, pszBuffer, iFileLength);

      for (int i=0;i<iBytesRead;i++)
        StringGrid1->RowCount += 1;
        StringGrid1->Cells[1][i+1] = pszBuffer[i];
        StringGrid1->Cells[2][i+1] = IntToStr((int)pszBuffer[i]);
      delete [] pszBuffer;
      Application->MessageBox("Can't perform one of the following file operations: Open, Seek, Read, Close.", "File Error", IDOK);

That came from online help of BCB6 using search for "FileOpen" and the topic is:
"FileOpen, FileSeek, FileRead Example"
It will be better if you post a bit of code to help you.

You would need to change the structure to use a char array in place of the AnsiString to make this work.

typedef struct ResFileStr_
char ImagePath[255];
 int RecognitionMethod;
 int Background,ThresholdMethod;
 float Recall,Precission;

Although it is in a plain structure,  the AnsiString is still not a plain data type.  It is kinda like only part of it is written out so when you try to read it back you don't get all the information you need reconstruct it properly.
POD - Plain Old Data,

Not the solution you were looking for? Getting a personalized solution is easy.

Ask the Experts
Jose ParrotGraphics Expert


Despite its type name, AnsiString is not a sequence of characters as one can think at glance. So you never will see Ansi characters sequence by reflecting the string form, although the content is the same.
So, if you write an AnsiString, must read it as a AnsiString; if you want to "type" the record and see characters as expected, say "C:\\di1\\dir2\\file.jpg", you must save it as char type, as kode99 suggests.

If you don't want to change so much your code, you can convert MyAnsiString to char simply by using MyAnsiString.c_str() conversion.

Also, as matter of consistency, when you write the file, you should open it as "wt" for text, instead of "wb" for binary. And, of course, for reading, open such file as "rt". That way your file will be pure ASCII characters and you can "type" it and read its content without problems.

>>Despite its type name, AnsiString is not a sequence of characters as one can think at glance
String.c_str() is....
I have used AnsiStrings the way the author describe and didn't have any problem using C++Builder functions...
Check out C++ Builder Developers Guide 5 & 6....

George Tokas.
Jose ParrotGraphics Expert

I'm talking about c code to use AnsiString. Not Builder c++.
     AnsiString ImagePath;

>>I'm talking about c code to use AnsiString. Not Builder c++.
If I'm not mistaken THIS IS C++ BUILDER TA...
What I wanted to say is that when we have a superset to use (BCB) why use the subset for (c)...
But because of the university the author is, I think that stucked with that...
No offence everybody....
No matter of any superiority over anything...
Just an oppinion...

George Tokas.

You just have to be careful when mixing c style code with c++.  This is an example of what can happen.  No error indicated it just will not work properly.  By adding the AnsiString you are adding a class to a struct.  A class contains functions and by definition a c struct is a data only form.  So functions like fwrite/fread which work fine for c struct variables just cannot handle the complexity of a c++ class.

For most situations the AnsiString in the struct will work just fine.  If you want to see another malfunction do a 'sizeof' on a AnsiString (without the c_str()),  the result will always be 4 no matter how long the string data is.  Not exactly the result intended and also no error indicated.

Unfortunatly c_str() will do no good for changing how the struct will be written to disk.  It would have to be used to convert AnsiString to a char array when assigning the ImagePath variable in the structure.  The downside is that you have to used a fixed length array for the name,  AnsiString is very convienient.

It would also be possible to write the ImagePath with 2 write operations in addition to writing the structure.  So write a integer length of the string first,  followed by the actual string and then write the structure and then the read back would have to be similar.  I think this is a hack though and could come back to haunt you later.

I would say the c++ way would be to use a class instead of a struct and then build the file io into the class properly.  In the end this approach leads to cleaner code and is much easier to manage in the long run.
Jose ParrotGraphics Expert

Hello, Sotiris Zegiannis,

Seems all comments posted confirm not mixing c and c++ as a good practice.
The c++ approach by using a class instead of a struct is the suggestion we would agree on, as pointed by kode99.

As you are using Builder C++, it is prefferable to take advantage of its features besides that of C++. And, if yours is an application to image processing, TImage is a perfect class to work with. You can draw primitives, load images directly, save and print its contents easely.

So, even if you'll need work a bit more, let me suggest to remake your application entirely by using C++. You can start by using the code provided by George Tokas. As you can see it uses a dialog to chose the image file you want, which is far superior to console style interactivity.

Please accept my appologies, extensive to the experts around, if I made more confusion than clarifying the subject in my previous comment, although the objective was to contribute.



I really appreciate everybone's help.At the end you where right code99,you can't mix c && c++.I put an array of chars in the struct and it worked fine.Thank you all very much.
Take Care.
I have something to add here.
I waited some time before posting this just to prove the point that I don't feel any kind of anger.
So dear Sotiri,
First of all:
>>At the end you where right code99,you can't mix c && c++
Yes you can. You can mix whatever you like even CPU register status. The problem is the right way to do it.

I can understand your "C" obsession of some kind because I know what you learn at the University. Many years OUTDATED.
My recomendation was to use BCB functions. And the reason is a bit simple.
If you are using BCB to write and compile a c listing it's like having a Ferrari on the road and drive it like a VW Beatle and the OLDEST of the models. That vehicle belongs to the museum along with c. Of course the same apply for VS and some other compilers.
Since we are almost all working in Windows what we are doing is to use the API one way or the other. Lower level functions at the most cases don't do any good.

There is a realy long talk about the above and I hope you Sotiri and the rest of the experts that you can see my point here.

George Tokas.
Access more of Experts Exchange with a free account
Thanks for using Experts Exchange.

Create a free account to continue.

Limited access with a free account allows you to:

  • View three pieces of content (articles, solutions, posts, and videos)
  • Ask the experts questions (counted toward content limit)
  • Customize your dashboard and profile

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.


Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.