[c++] get() and read() function from fstream

Discussion in 'C++' started by ZikO, Feb 4, 2009.

  1. ZikO

    ZikO Guest

    Hi.

    Im using C++ Compiler as below:
    g++ (GCC) 4.3.0 20080305 (alpha-testing) mingw-20080502
    Copyright (C) 2008 Free Software Foundation, Inc.

    Im writing the simple program which is supposed to give info about sound
    wave file. It checks whether a file is a wave format (4 ASCII bytes
    should be like {'R','I','F','F'}) and then it reads what the size of the
    file is (another 4 bytes). However, I found difficult to understand how
    to use both get() and read() functions properly which are in <fstream>
    library.

    there is the code below in which I check if file starts with "RIFF". I
    have used waveFile.get() function to obtain 4 bytes from the input
    stream, although I wanted read() before. I had to use get() because if I
    used read() instead the program would go straight to else branch and
    display "This is not a wave file", even if it is.

    Any suggestions why read() does not work here?

    Thanks.



    PS. The test file can be found here:
    http://rapidshare.de/files/44749739/test.wav.html

    Code:
    ..#include <iostream>
    ..#include <fstream>
    ..#include <cstring>
    ..
    ..using namespace std;
    ..
    ..void checkStream(ifstream& in_str) {
    ..  // if() {} ...
    ..  return;
    ..}
    ..
    ..int main() {
    ..  ifstream waveFile("test.txt");
    ..  int filePointer = 0;
    ..  char temp[5] = {0,0,0,0};
    ..  if(waveFile.get(temp,4)) {
    ..    // cout << "stream pointer = " << waveFile.tellg() << endl;
    ..    filePointer += 4;
    ..    char waveChunk[] = {"RIFF"};
    ..    if(strcmp(temp, waveChunk)) {
    ..      cout << "This is a wave file." << endl;
    ..    }
    ..    else {
    ..      cout << "This is not a wave file" << endl;
    ..      return 0;
    ..    }
    ..  }
    ..  else
    ..    checkStream(waveFile);
    ..
    ..  int roz;
    ..  waveFile.seekg(filePointer);
    ..  if(waveFile.read(reinterpret_cast<char*>(&roz), 4)) {
    ..    filePointer += 4;
    ..    roz += 8;
    ..    cout << "The size is: " << roz << endl;
    ..  }
    ..  else
    ..  checkStream(waveFile);
    ..}
    
     
    ZikO, Feb 4, 2009
    #1
    1. Advertising

  2. ZikO

    James Kanze Guest

    Re: get() and read() function from fstream

    On Feb 4, 8:40 pm, ZikO <> wrote:
    > Im using C++ Compiler as below:
    > g++ (GCC) 4.3.0 20080305 (alpha-testing) mingw-20080502
    > Copyright (C) 2008 Free Software Foundation, Inc.


    > Im writing the simple program which is supposed to give info
    > about sound wave file. It checks whether a file is a wave
    > format (4 ASCII bytes should be like {'R','I','F','F'}) and
    > then it reads what the size of the file is (another 4 bytes).
    > However, I found difficult to understand how to use both get()
    > and read() functions properly which are in <fstream> library.


    > there is the code below in which I check if file starts with
    > "RIFF". I have used waveFile.get() function to obtain 4 bytes
    > from the input stream, although I wanted read() before. I had
    > to use get() because if I used read() instead the program
    > would go straight to else branch and display "This is not a
    > wave file", even if it is.


    > Any suggestions why read() does not work here?


    Not really, but there are a number of problems in your code.

    >
    Code:
    > .#include <iostream>
    > .#include <fstream>
    > .#include <cstring>[/color]
    [color=blue]
    > .using namespace std;[/color]
    [color=blue]
    > .void checkStream(ifstream& in_str) {
    > .  // if() {} ...
    > .  return;
    > .}[/color]
    [color=blue]
    > .int main() {
    > .  ifstream waveFile("test.txt");[/color]
    
    The wave format contains binary data, so you must open the file
    in binary mode.  Otherwise, your code will only work on Unix and
    Unix look-alikes (where binary and text modes are identical).
    
        std::ifstream waveFile( "test.txt", std::ios::binary ) ;
    
    (Also, .txt is a very strange filename ending for a binary file.
    If you're dealing with wave files, I'd expect something like
    ..wav.)
    
    And are you sure the open succeeded.  You need to test the
    status immediately:
    
        if ( ! waveFile ) {
            fatalError( "cannot open test.txt" ) ;
        }
    [color=blue]
    > .  int filePointer = 0;[/color]
    
    Almost certainly not a problem in your tests, but int is
    generallly not big enough to hold a position in a file.  I'd use
    either std::streampos or long long.
    [color=blue]
    > .  char temp[5] = {0,0,0,0};[/color]
    
    Just {} would be sufficient.  Interestingly enough the only byte
    you really need initialized is the last, which is the only one
    you don't initialize explicitly (but as soon as the initializer
    list is present, all elements without an explicit initializer
    are initialized as 0.
    [color=blue]
    > .  if(waveFile.get(temp,4)) {
    > .    // cout << "stream pointer = " << waveFile.tellg() << endl;
    > .    filePointer += 4;
    > .    char waveChunk[] = {"RIFF"};
    > .    if(strcmp(temp, waveChunk)) {[/color]
    
    What's wrong with just strcmp( temp, "RIFF" ) ?
    [color=blue]
    > .      cout << "This is a wave file." << endl;
    > .    }
    > .    else {
    > .      cout << "This is not a wave file" << endl;
    > .      return 0;
    > .    }
    > .  }
    > .  else
    > .    checkStream(waveFile);[/color]
    [color=blue]
    > .  int roz;
    > .  waveFile.seekg(filePointer);
    > .  if(waveFile.read(reinterpret_cast<char*>(&roz), 4)) {[/color]
    
    And this won't necessarily work.  You can't just read raw binary
    data.  You have a binary file with a specific format.  That
    format isn't directly supported by the standard, so you have to
    implement it yourself.
    
    From what little information I've found, you need to do
    something like:
    
        unsigned long
        readWaveInt(
            std::istream&   source )
        {
            unsigned long   result = 0 ;
            for ( int shift = 0 ; shift != 32 ; shift += 8 ) {
                result |= source.get() << shift ;
            }
            return result ;
        }
    
    (This will return some random value if you encounter EOF within
    the function, but in this case, the call to get should set
    failbit, so you can detect the error by testing source.)
    
    Note that this is *not* the usual external format for an int.
    [color=blue]
    > .    filePointer += 4;
    > .    roz += 8;
    > .    cout << "The size is: " << roz << endl;
    > .  }
    > .  else
    > .  checkStream(waveFile);
    > .}
    > 


    If this code outputs "This is not a wave file", either you've
    not successfully opened the file, or the first four bytes aren't
    "RIFF" (or you're on a platform where the native character
    encoding isn't an extension of ASCII, but that's highly
    unlikely---I don't think you'd be reading wave files on a
    mainframe).

    --
    James Kanze (GABI Software) email:
    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
     
    James Kanze, Feb 5, 2009
    #2
    1. Advertising

  3. ZikO

    ZikO Guest

    Re: get() and read() function from fstream

    James Kanze wrote:
    >> . char temp[5] = {0,0,0,0};


    It's funny. Just missed last 0, the strange think is the compiler did
    not warn that, however,
    char temp[5];
    works perfectly. Thnx.

    > What's wrong with just strcmp( temp, "RIFF" ) ?


    Nothing.

    > From what little information I've found, you need to do
    > something like:
    >
    > unsigned long
    > readWaveInt(
    > std::istream& source )
    > {
    > unsigned long result = 0 ;
    > for ( int shift = 0 ; shift != 32 ; shift += 8 ) {
    > result |= source.get() << shift ;
    > }
    > return result ;
    > }
    >


    I like this idea. Probably will help me avoid many problems. Thanks.


    > If this code outputs "This is not a wave file", either you've
    > not successfully opened the file, or the first four bytes aren't
    > "RIFF" (or you're on a platform where the native character
    > encoding isn't an extension of ASCII, but that's highly
    > unlikely---I don't think you'd be reading wave files on a
    > mainframe).


    The problem is very trivial ^^. strcmp() returns 0 if strings are equal.
    Unfortunately, 0 means false in if() statement which I didnt know. I was
    sue strcmp would return bool true/false. This is another reason to stop
    using old <cstring>

    Thanks for the constructive suggestions =)
     
    ZikO, Feb 5, 2009
    #3
  4. ZikO

    James Kanze Guest

    Re: get() and read() function from fstream

    On Feb 5, 12:41 pm, ZikO <> wrote:
    > James Kanze wrote:
    > >> . char temp[5] = {0,0,0,0};


    > It's funny. Just missed last 0, the strange think is the
    > compiler did not warn that,


    Not really. The standard says if there is an initializer,
    anything left over without initialization is zero initialized.
    So you can write things like:

    int array[ 1000 ] = {} ;

    and get the entire array initialized. And I certainly don't
    want to have to write out 1000 0's just to avoid a warning.
    (G++ does warn, and it gets on my nerves.)

    > however,
    > char temp[5];
    > works perfectly.


    Only if it's static, or you do something to force the last byte
    to 0. (Some compilers do zero the memory. Others do so only in
    debugging mode.)

    [...]
    > > From what little information I've found, you need to do
    > > something like:


    > > unsigned long
    > > readWaveInt(
    > > std::istream& source )
    > > {
    > > unsigned long result = 0 ;
    > > for ( int shift = 0 ; shift != 32 ; shift += 8 ) {
    > > result |= source.get() << shift ;
    > > }
    > > return result ;
    > > }


    > I like this idea. Probably will help me avoid many problems.


    In the end, it's the only thing that works portably.

    Since wave files were designed by Microsoft, for Intel based
    processors, just reading the raw bytes into the int will work
    under Windows. It won't work on the machine I usually work on,
    nor on a lot of other machines.

    > > If this code outputs "This is not a wave file", either
    > > you've not successfully opened the file, or the first four
    > > bytes aren't "RIFF" (or you're on a platform where the
    > > native character encoding isn't an extension of ASCII, but
    > > that's highly unlikely---I don't think you'd be reading wave
    > > files on a mainframe).


    > The problem is very trivial ^^. strcmp() returns 0 if strings
    > are equal. Unfortunately, 0 means false in if() statement
    > which I didnt know. I was sue strcmp would return bool
    > true/false. This is another reason to stop using old <cstring>


    I saw that. It's funny I didn't spot it myself, but in my
    experience, the only people who use char[] and <string.h> are
    ex-C hackers, who generally get these sort of things right, so I
    didn't look too carefully.

    --
    James Kanze
     
    James Kanze, Feb 5, 2009
    #4
    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. Armando
    Replies:
    6
    Views:
    747
    Armando
    Jan 29, 2004
  2. Christian Henke

    fstream messes up order at read out

    Christian Henke, Mar 6, 2004, in forum: C++
    Replies:
    7
    Views:
    437
    Christian Henke
    Mar 7, 2004
  3. dumboo

    fstream::read(..);

    dumboo, May 18, 2004, in forum: C++
    Replies:
    2
    Views:
    5,098
    dumboo
    May 18, 2004
  4. Don Kim
    Replies:
    13
    Views:
    796
    Francis Glassborow
    Jan 24, 2005
  5. Sachin Garg
    Replies:
    1
    Views:
    487
    Ron AF Greve
    Aug 22, 2008
Loading...

Share This Page