[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.c++

reading / writing a string

hamishd

12/3/2008 3:29:00 PM

Hi, I have a structure like this:

#define MAX_LENGTH 20

struct InformationClass
{
char StringA[MAX_LENGTH];
char StringB[MAX_LENGTH];
};

I want to be able to write it to a file, and also read it back in
again? I am using fprintf, and fscanf.

Write like this:
fprintf(stream, "%s%s", IC.StringA, IC.StringB);

Read like this:
fscanf(stream, "%s%s", &IC.StringA, &IC.StringB);

It doesn't seem to work. Is there an easy way to do this?

5 Answers

Jeff Schwab

12/3/2008 3:54:00 PM

0

hamishd wrote:
> Hi, I have a structure like this:
>
> #define MAX_LENGTH 20
>
> struct InformationClass
> {
> char StringA[MAX_LENGTH];
> char StringB[MAX_LENGTH];
> };
>
> I want to be able to write it to a file, and also read it back in
> again? I am using fprintf, and fscanf.
>
> Write like this:
> fprintf(stream, "%s%s", IC.StringA, IC.StringB);

Here, you write the strings back-to-back, without any intervening
whitespace. When you try to read the strings back into your program,
the whole sequence will be mistaken for one string. You could try
inserting a space, so that the format string is "%s %s".

> Read like this:
> fscanf(stream, "%s%s", &IC.StringA, &IC.StringB);
>
> It doesn't seem to work. Is there an easy way to do this?

The "easy" way is to use the C++ standard library's stream and string
types, and to follow some basic conventions with regard to operator
overloading. This may seem cryptic to you at first, but it is worth
taking the time to understand; the effort pays off quickly.

#include <fstream>
#include <iostream>
#include <string>

struct information {
std::string string_a;
std::string string_b;
};

std::ostream& operator<<(
std::ostream& stream,
information const& info) {
return stream << info.string_a << ' ' << info.string_b;
}

std::istream& operator>>(
std::istream& stream,
information& info) {
return stream >> info.string_a >> info.string_b;
}

void write_file(char const* name, information const& info) {
std::ofstream stream( name );
stream << info;
}

information read_file(char const* name) {
std::ifstream stream( name );
information info;
stream >> info;
return info;
}

int main() {
information const info = { "hello", "world" };
char const file_name[] = "some_file";
write_file(file_name, info);
std::cout << read_file(file_name) << '\n';
return 0;
}

Fred

12/3/2008 7:14:00 PM

0

On Dec 3, 7:54 am, Jeff Schwab <j...@schwabcenter.com> wrote:
> hamishd wrote:
> > Hi, I have a structure like this:
>
> > #define MAX_LENGTH 20
>
> > struct InformationClass
> > {
> >    char StringA[MAX_LENGTH];
> >    char StringB[MAX_LENGTH];
> > };
>
> > I want to be able to write it to a file, and also read it back in
> > again? I am using fprintf, and fscanf.
>
> > Write like this:
> > fprintf(stream, "%s%s", IC.StringA, IC.StringB);
>
> Here, you write the strings back-to-back, without any intervening
> whitespace.  When you try to read the strings back into your program,
> the whole sequence will be mistaken for one string.  You could try
> inserting a space, so that the format string is "%s %s".
>
> > Read like this:
> > fscanf(stream, "%s%s", &IC.StringA, &IC.StringB);
>
> > It doesn't seem to work. Is there an easy way to do this?
>
> The "easy" way is to use the C++ standard library's stream and string
> types, and to follow some basic conventions with regard to operator
> overloading.  This may seem cryptic to you at first, but it is worth
> taking the time to understand; the effort pays off quickly.
>
> #include <fstream>
> #include <iostream>
> #include <string>
>
> struct information {
>      std::string string_a;
>      std::string string_b;
>
> };
>
> std::ostream& operator<<(
>          std::ostream& stream,
>          information const& info) {
>      return stream << info.string_a << ' ' << info.string_b;
>
> }
>
> std::istream& operator>>(
>          std::istream& stream,
>          information& info) {
>      return stream >> info.string_a >> info.string_b;
>
> }
>
> void write_file(char const* name, information const& info) {
>      std::ofstream stream( name );
>      stream << info;
>
> }
>
> information read_file(char const* name) {
>      std::ifstream stream( name );
>      information info;
>      stream >> info;
>      return info;
>
> }
>
> int main() {
>      information const info = { "hello", "world" };
>      char const file_name[] = "some_file";
>      write_file(file_name, info);
>      std::cout << read_file(file_name) << '\n';
>      return 0;
>
>
>
> }- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -

This still will not work if either of the strings contains embedded
whitespace.
--
Fred K

KK

12/3/2008 7:35:00 PM

0

On Dec 3, 11:14 am, Fred <fred.l.kleinschm...@boeing.com> wrote:
> On Dec 3, 7:54 am, Jeff Schwab <j...@schwabcenter.com> wrote:
>
>
>
> > hamishd wrote:
> > > Hi, I have a structure like this:
>
> > > #define MAX_LENGTH 20
>
> > > struct InformationClass
> > > {
> > >    char StringA[MAX_LENGTH];
> > >    char StringB[MAX_LENGTH];
> > > };
>
> > > I want to be able to write it to a file, and also read it back in
> > > again? I am using fprintf, and fscanf.
>
> > > Write like this:
> > > fprintf(stream, "%s%s", IC.StringA, IC.StringB);
>
> > Here, you write the strings back-to-back, without any intervening
> > whitespace.  When you try to read the strings back into your program,
> > the whole sequence will be mistaken for one string.  You could try
> > inserting a space, so that the format string is "%s %s".
>
> > > Read like this:
> > > fscanf(stream, "%s%s", &IC.StringA, &IC.StringB);
>
> > > It doesn't seem to work. Is there an easy way to do this?
>
> > The "easy" way is to use the C++ standard library's stream and string
> > types, and to follow some basic conventions with regard to operator
> > overloading.  This may seem cryptic to you at first, but it is worth
> > taking the time to understand; the effort pays off quickly.
>
> > #include <fstream>
> > #include <iostream>
> > #include <string>
>
> > struct information {
> >      std::string string_a;
> >      std::string string_b;
>
> > };
>
> > std::ostream& operator<<(
> >          std::ostream& stream,
> >          information const& info) {
> >      return stream << info.string_a << ' ' << info.string_b;
>
> > }
>
> > std::istream& operator>>(
> >          std::istream& stream,
> >          information& info) {
> >      return stream >> info.string_a >> info.string_b;
>
> > }
>
> > void write_file(char const* name, information const& info) {
> >      std::ofstream stream( name );
> >      stream << info;
>
> > }
>
> > information read_file(char const* name) {
> >      std::ifstream stream( name );
> >      information info;
> >      stream >> info;
> >      return info;
>
> > }
>
> > int main() {
> >      information const info = { "hello", "world" };
> >      char const file_name[] = "some_file";
> >      write_file(file_name, info);
> >      std::cout << read_file(file_name) << '\n';
> >      return 0;
>
> > }- Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -
>
> > - Show quoted text -
>
> This still will not work if either of the strings contains embedded
> whitespace.
> --
> Fred K

check getline() where you can specify a delimiter. You could use '\n'
as delimiter while writing a strings in different lines

Jeff Schwab

12/3/2008 7:45:00 PM

0

Fred wrote:
> On Dec 3, 7:54 am, Jeff Schwab <j...@schwabcenter.com> wrote:

>>> fprintf(stream, "%s%s", IC.StringA, IC.StringB);

>> Here, you write the strings back-to-back, without any intervening
>> whitespace. When you try to read the strings back into your program,
>> the whole sequence will be mistaken for one string. You could try
>> inserting a space, so that the format string is "%s %s".

> This still will not work if either of the strings contains embedded
> whitespace.

Good point. That did not occur to me.

In general, there is no way to recover strings without adding some kind
of markup. The kind of inline markup I suggested must be outside the
set of valid values; either the markup must not occur in the original
strings (e.g. a null char may be used to terminate or separate C-style
strings, and whitespace may be used to separate strings of
non-whitespace), or it must be treated specially if it does occur (hence
&lt; and &amp; in XML). Another technique is to prefix a stream of
strings (or other serialized objects) with a header describing the
element sizes. In effect, data are meaningless without metadata. Very
Hofstadterian.

James Kanze

12/3/2008 10:21:00 PM

0

On Dec 3, 8:44 pm, Jeff Schwab <j...@schwabcenter.com> wrote:
> Fred wrote:
> > On Dec 3, 7:54 am, Jeff Schwab <j...@schwabcenter.com> wrote:
> >>> fprintf(stream, "%s%s", IC.StringA, IC.StringB);
> >> Here, you write the strings back-to-back, without any
> >> intervening whitespace.  When you try to read the strings
> >> back into your program, the whole sequence will be mistaken
> >> for one string.  You could try inserting a space, so that
> >> the format string is "%s %s".
> > This still will not work if either of the strings contains
> > embedded whitespace.

> Good point.  That did not occur to me.

It's a general problem when serializing in text format.
Choosing a separator for most types is fairly trivial, however;
there are lots of characters which can't show up in the string
representation an int or a double. (But it still requires some
thought---the C++ standard for formatting a complex regretfully
uses a separator which can occur in a double, which means that a
standard conforming implementation is totally useless.) For
strings in general, it's a bit more complicated. Most strings,
however, have a semantic, e.g. family name, or something like
that, which will forbid some characters, and thus allow a
separator; if not, I've written a ParsableString class which
ensures round trip serialization, roughly by using the
conventions for C++ string literals: in quotes, with quotes and
unprintable characters escaped.

--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34