Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   Re: iostream >> string, but fixed length string - how? (http://www.velocityreviews.com/forums/t721875-re-iostream-string-but-fixed-length-string-how.html)

Victor Bazarov 04-30-2010 01:10 PM

Re: iostream >> string, but fixed length string - how?
 
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

cpp4ever 04-30-2010 01:14 PM

Re: iostream >> string, but fixed length string - how?
 
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


Alf P. Steinbach 05-03-2010 07:16 AM

Re: iostream >> string, but fixed length string - how?
 
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


All times are GMT. The time now is 04:45 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.