Re: iostream >> string, but fixed length string - how?

Discussion in 'C++' started by Victor Bazarov, Apr 30, 2010.

  1. On 4/30/2010 8:38 AM, Adam Nielsen wrote:
    > I'd like to read a fixed number of bytes from a binary file into a
    > std::string. I have been doing this sort of thing:
    >
    > char foo[123];
    > stream.read(foo, 123);
    > std::string bar(foo);


    That's just not right. You don't control the size of the resulting
    'bar' string at all, a random occurrence of the null character does.
    Besides, if the 123 chars you read from the stream don't have a null
    character in them, the constructor for your 'bar' object will have
    undefined behavior because it will read past the array. At least you
    should do

    std::string bar(foo, foo+123);

    > However I would like to use iostream operators to make the code a bit easier
    > to read, but I'm not sure how to read in a fixed length string...


    What you do is the only way to "read the fixed length string". The
    shift operator is a part of the *formatted* I/O, which means the stream
    contents should control the outcome as much as you might. Strings are
    read until whitespace is encountered.

    You're much better off using 'read' for your purposes. You can define
    your 'bar' to contain 123 chars to begin with, and then read directly
    into its buffer if you think it's better. Something like

    std::string bar(123, 0);
    stream.read(bar.data(), 123);

    Also, don't forget to add error checking.

    > std::string foo;
    > stream>> std::setw(123)>> foo;
    >
    > Of course that doesn't work (it just reads to the first whitespace character),
    > so any suggestions would be much appreciated!


    My personal preference is to use unformatted I/O for reading binary
    files and formatted I/O for text files, but that's just me.

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Apr 30, 2010
    #1
    1. Advertising

  2. Victor Bazarov

    cpp4ever Guest

    On 04/30/2010 02:10 PM, Victor Bazarov wrote:
    > On 4/30/2010 8:38 AM, Adam Nielsen wrote:
    >> I'd like to read a fixed number of bytes from a binary file into a
    >> std::string. I have been doing this sort of thing:
    >>
    >> char foo[123];
    >> stream.read(foo, 123);
    >> std::string bar(foo);

    >
    > That's just not right. You don't control the size of the resulting
    > 'bar' string at all, a random occurrence of the null character does.
    > Besides, if the 123 chars you read from the stream don't have a null
    > character in them, the constructor for your 'bar' object will have
    > undefined behavior because it will read past the array. At least you
    > should do
    >
    > std::string bar(foo, foo+123);
    >
    >> However I would like to use iostream operators to make the code a bit
    >> easier
    >> to read, but I'm not sure how to read in a fixed length string...

    >
    > What you do is the only way to "read the fixed length string". The
    > shift operator is a part of the *formatted* I/O, which means the stream
    > contents should control the outcome as much as you might. Strings are
    > read until whitespace is encountered.
    >
    > You're much better off using 'read' for your purposes. You can define
    > your 'bar' to contain 123 chars to begin with, and then read directly
    > into its buffer if you think it's better. Something like
    >
    > std::string bar(123, 0);
    > stream.read(bar.data(), 123);
    >
    > Also, don't forget to add error checking.
    >
    >> std::string foo;
    >> stream>> std::setw(123)>> foo;
    >>
    >> Of course that doesn't work (it just reads to the first whitespace
    >> character),
    >> so any suggestions would be much appreciated!

    >
    > My personal preference is to use unformatted I/O for reading binary
    > files and formatted I/O for text files, but that's just me.
    >
    > V


    I like Mr V, reminds me of the ice cream van as a kid, comes along with
    a cool simple solution on a hot bothersome day.

    Regards

    JB
    cpp4ever, Apr 30, 2010
    #2
    1. Advertising

  3. On 30.04.2010 15:28, * Adam Nielsen:
    >>> char foo[123];
    >>> stream.read(foo, 123);
    >>> std::string bar(foo);

    >>
    >> That's just not right. You don't control the size of the resulting
    >> 'bar' string at all, a random occurrence of the null character does.
    >> Besides, if the 123 chars you read from the stream don't have a null
    >> character in them, the constructor for your 'bar' object will have
    >> undefined behavior because it will read past the array. At least you
    >> should do
    >>
    >> std::string bar(foo, foo+123);

    >
    > Sorry, I should have explained it was just some pseudocode, simplified to
    > illustrate my point. However sometimes I am reading a null terminated string,
    > padded to fill up the 123 chars. So reading 123 chars from the file and
    > ending up with a much shorter string (with the file pointer in the right place
    > for the next field to be read) is indeed correct. Also if I understand
    > correctly your example should read:
    >
    > std::string bar(foo, 123);
    >
    > As the second argument is a length, not a pointer or iterator.


    You can use either form, corresponding to two different constructors.

    Victor's is more idiomatic.



    >> What you do is the only way to "read the fixed length string". The
    >> shift operator is a part of the *formatted* I/O, which means the stream
    >> contents should control the outcome as much as you might. Strings are
    >> read until whitespace is encountered.

    >
    > Ah ok, well that answers my question, thanks!
    >
    >> You're much better off using 'read' for your purposes. You can define
    >> your 'bar' to contain 123 chars to begin with, and then read directly
    >> into its buffer if you think it's better. Something like
    >>
    >> std::string bar(123, 0);
    >> stream.read(bar.data(), 123);

    >
    > I had also tried this, but alas both data() and c_str() return const pointers
    > so it seems you're not supposed to be able to do this. I'm not sure whether
    > const_casting this away is a good idea or not...


    Just use

    stream.read( &bar[0], 123 );



    >> My personal preference is to use unformatted I/O for reading binary
    >> files and formatted I/O for text files, but that's just me.

    >
    > I see your point, but as I am reading a number of fields from a file I find
    > syntax along these lines much clearer:
    >
    > std::string filename;
    > int offset, size;
    >
    > stream>> filename
    > >> u32le(offset)
    > >> u16le(size);

    >
    > In this particular case, writing all that out using the unformatted I/O
    > functions makes for a much less concise result.


    Might be OK for personal code, but don't do that for code that others would have
    to relate to.

    "<<" and ">>" for streams very very strongly indicate textual formatted i/o.


    Cheers & hth.,

    - Alf
    Alf P. Steinbach, May 3, 2010
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Tiger
    Replies:
    10
    Views:
    5,584
  2. ai@work
    Replies:
    9
    Views:
    540
    Ron Natalie
    Dec 16, 2004
  3. S. Nurbe

    iostream + iostream.h

    S. Nurbe, Jan 14, 2005, in forum: C++
    Replies:
    7
    Views:
    770
    red floyd
    Jan 15, 2005
  4. red floyd
    Replies:
    3
    Views:
    534
    Dietmar Kuehl
    Mar 8, 2005
  5. cpp4ever
    Replies:
    2
    Views:
    888
    cpp4ever
    May 4, 2010
Loading...

Share This Page