Solved

Write to binary File,struct with AnsiString.

Posted on 2006-11-06
12
4,716 Views
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;
}ResFileStr;

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.

0
Comment
Question by:sotiris_zegiannis
  • 5
  • 3
  • 2
  • +1
12 Comments
 
LVL 16

Expert Comment

by:George Tokas
ID: 17881456
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.

Now:
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.
0
 

Author Comment

by:sotiris_zegiannis
ID: 17881822
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.
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17882553
>>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())
  {
    try
    {
      iFileHandle = FileOpen(OpenDialog1->FileName, fmOpenRead);
      iFileLength = FileSeek(iFileHandle,0,2);
      FileSeek(iFileHandle,0,0);
      pszBuffer = newchar[iFileLength+1];
      iBytesRead = FileRead(iFileHandle, pszBuffer, iFileLength);
      FileClose(iFileHandle);

      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;
    }
    catch(...)
    {
      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.

George.
0
 
LVL 25

Accepted Solution

by:
kode99 earned 500 total points
ID: 17883301
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;
}ResFileStr;

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,
http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.7


0
 
LVL 18

Expert Comment

by:JoseParrot
ID: 17893468
Hi,

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.

Jose
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17894444
>>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.
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 18

Expert Comment

by:JoseParrot
ID: 17894744
I'm talking about c code to use AnsiString. Not Builder c++.
Example:
     AnsiString ImagePath;
     fopen(ImagePath.c_str(),"rb");

Jose
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17895079
>>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.
0
 
LVL 25

Expert Comment

by:kode99
ID: 17896141
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.
0
 
LVL 18

Expert Comment

by:JoseParrot
ID: 17897757
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.

Jose
0
 

Author Comment

by:sotiris_zegiannis
ID: 17901204
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.
Sotos.
0
 
LVL 16

Expert Comment

by:George Tokas
ID: 17911212
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.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now