Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 4794
  • Last Modified:

Write to binary File,struct with AnsiString.

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
sotiris_zegiannis
Asked:
sotiris_zegiannis
  • 5
  • 3
  • 2
  • +1
1 Solution
 
George TokasCommented:
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
 
sotiris_zegiannisAuthor Commented:
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
 
George TokasCommented:
>>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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
kode99Commented:
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
 
Jose ParrotGraphics ExpertCommented:
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
 
George TokasCommented:
>>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
 
Jose ParrotGraphics ExpertCommented:
I'm talking about c code to use AnsiString. Not Builder c++.
Example:
     AnsiString ImagePath;
     fopen(ImagePath.c_str(),"rb");

Jose
0
 
George TokasCommented:
>>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
 
kode99Commented:
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
 
Jose ParrotGraphics ExpertCommented:
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
 
sotiris_zegiannisAuthor Commented:
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
 
George TokasCommented:
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 5
  • 3
  • 2
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now