12 Replies - 1197 Views - Last Post: 20 July 2013 - 03:34 PM Rate Topic: -----

#1 unknown500   User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 30
  • Joined: 11-June 12

Reading A Binary .DAT file

Posted 16 July 2013 - 08:24 PM

I am having some trouble reading in a .dat file in my c++ program. I can write to the file, but when I try to read it afterwards, the program crashes. Any help with this would be greatly appreciated!

P.S. I attached the file that I am trying to read to this post (music_organizer.dat). It contains one music file for testing purposes.

The program is a music inventory program. So, I have a MusicFile.cpp class to represent a single music file. This class seems to be working fine:

/**
 *  MusicFile.cpp - Class IMPLEMENTATION for a music file.  This class 
 *                 will be a single node in the linked list.
 *
 * Course: CS3330 Data Structures and Algorithms.
 * Instructor: Dr. Jack Davault
 */

#include "MusicFile.h"

//Constructor definitions

MusicFile::MusicFile()  //Access MusicFile class by typing MusicFile::
{
   // Currently does nothing ...
}

// Copy constructor
MusicFile::MusicFile(const MusicFile &musicFile)
{
   this->recordNumber = musicFile.recordNumber;
   this->name = musicFile.name;
   this->length = musicFile.length;
   this->artist = musicFile.artist;
   this->album = musicFile.album;
   this->genre = musicFile.genre;
   this->rating = musicFile.rating;
   this->numberOfTimesPlayed = musicFile.numberOfTimesPlayed;
   this->fileName = musicFile.fileName;
}

MusicFile::~MusicFile()
{
   // Currently does nothing ...
}


//Function definitions

void MusicFile::setRecordNumber(const int recordNumber)
{
   this->recordNumber = recordNumber;
}

int MusicFile::getRecordNumber() const
{
   return recordNumber;
}

void MusicFile::setName(const string name)
{
   this->name = name;
}

string MusicFile::getName() const
{
   return name;
}

void MusicFile::setLength(const string length)
{
   this->length = length;
}

string MusicFile::getLength() const
{
   return length;
}

void MusicFile::setArtist(const string artist)
{
   this->artist = artist;
}

string MusicFile::getArtist() const
{
   return artist;
}

void MusicFile::setAlbum(const string album)
{
   this->album = album;
}

string MusicFile::getAlbum() const
{
   return album;
}
void MusicFile::setGenre(const string genre)
{
   this->genre = genre;
}

string MusicFile::getGenre() const
{
   return genre;
}
void MusicFile::setRating(const int rating)
{
   this->rating = rating;
}

int MusicFile::getRating() const
{
   return rating;
}
void MusicFile::setNumberOfTimesPlayed(int numberOfTimesPlayed)
{
   this->numberOfTimesPlayed = numberOfTimesPlayed;
}

int MusicFile::getNumberOfTimesPlayed() const
{
   return numberOfTimesPlayed;
}
void MusicFile::setFileName(string fileName)
{
   this->fileName = fileName;
}

string MusicFile::getFileName() const
{
   return fileName;
}




Then, I have a MusicInventory.cpp class to display all the music files in the inventory. I think my program crashes on line 67 in this class:
my_file.read((char *)&song, sizeof(song));


using namespace std;

//Function declarations
void menu();
void loadFile();
void saveFile();

//Member declarations
list <MusicFile> musicList; 

//Main Function. Loads in the music_organizer.dat file & then displays the menu.
int main(){
   loadFile();
   
    menu();
    
    return 0;
}

/* 
 * This function provides the main menu for the user.
 */
void menu()
{
   string userOption;
   bool exitProgram = false;
  
   while (!exitProgram)
   {
      // Allow the user to select options to add, delete, modify, and 
      // list all data in the music list.
      cout << endl << "** MUSIC INVENTORY V1.1 MAIN MENU **" << endl << endl;
      cout << "   1. Add entry" << endl;
      cout << "   2. Delete entry" << endl;
      cout << "   3. Display entries" << endl;
      cout << "   4. Search for Album" << endl;
      cout << "   5. Modify a Song" << endl;
      cout << endl << "   99. Exit program" << endl << endl;
   
      cout << "Option> ";
      getline(cin, userOption, '\n');
   
      // Process user entry
      switch (atoi(userOption.c_str()))
      {
         ...

         // Save musiclist to "music_organizer".dat and then exit program
          case 99:
               saveFile();
              exitProgram = true;
            break;

          default:
            cerr << "Error: unknown option!" << endl;
            break;
      }
   }

   return;    
}

void loadFile(){
    ifstream my_file;
    my_file.open("music_organizer.dat", ios::binary);
    MusicFile song;
    my_file.read((char *)&song, sizeof(song)); //This is where the program crashes!
    my_file.close();
}

void saveFile(){

     ofstream my_file;
     my_file.open("music_organizer.dat", ios::binary);
     
     if(!my_file){
       //If file doesn't exist create it here
        ofstream my_file("music_organizer.dat", ios::binary);
     }
    
    //Write every music file in the linked list musicList to the "music_organizer.dat" file 
      
      list<MusicFile>::iterator musicFile;
      for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
   {
       my_file.write((char*)&musicFile, sizeof(musicFile));      
   }
   my_file.close();
}


This post has been edited by unknown500: 16 July 2013 - 08:26 PM


Is This A Good Question/Topic? 0
  • +

Replies To: Reading A Binary .DAT file

#2 jimblumberg   User is offline

  • member icon

Reputation: 5549
  • View blog
  • Posts: 17,176
  • Joined: 25-December 09

Re: Reading A Binary .DAT file

Posted 16 July 2013 - 08:28 PM

Where is your data file? You'll probably need to change the extension to .txt in order to attach it.


What include files are you including?

Jim

This post has been edited by jimblumberg: 16 July 2013 - 08:29 PM

Was This Post Helpful? 0
  • +
  • -

#3 darknessx   User is offline

  • New D.I.C Head

Reputation: 1
  • View blog
  • Posts: 31
  • Joined: 18-June 13

Re: Reading A Binary .DAT file

Posted 16 July 2013 - 09:01 PM

One ideia is... use of another type of file stream to open. except of ofstream or ifstream.

like this one
FILE* stream;
char* mode;

mode = "ab+"; //Append, Create, Open, Write at file last line (or character)

stream = fopen("Filename",mode);



and if you want to get some information into the file you can use fget
and if you want to put some information you use fput

at least after you make all your operations into the file you close the handler with fclose
fclose(stream);



so its a idea. and you can try this if you want.
Was This Post Helpful? -1
  • +
  • -

#4 #define   User is offline

  • Duke of Err
  • member icon

Reputation: 1854
  • View blog
  • Posts: 6,673
  • Joined: 19-February 09

Re: Reading A Binary .DAT file

Posted 17 July 2013 - 12:58 PM

Hi, your MusicFile class contains strings, which are a basically like pointers to data in dynamic memory. When you save the class to file you are not saving the data. So it cannot be read.
Was This Post Helpful? 1
  • +
  • -

#5 unknown500   User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 30
  • Joined: 11-June 12

Re: Reading A Binary .DAT file

Posted 17 July 2013 - 07:56 PM

View Postjimblumberg, on 16 July 2013 - 08:28 PM, said:

Where is your data file? You'll probably need to change the extension to .txt in order to attach it.


What include files are you including?

Jim

Hi, Jim. Thank you for your help.

I attached the file again (as a .txt this time). Let me know if you can see it now. If you view it in Notepad++, it should have some information it.

In my MusicInventory.cpp, I have the following includes:
#include "MusicFile.h"
#include <list> //STL linked list
#include <iostream> //To use cin
#include <fstream> //To use fstream for file maninpulation


This post has been edited by unknown500: 17 July 2013 - 07:58 PM

Was This Post Helpful? 0
  • +
  • -

#6 jimblumberg   User is offline

  • member icon

Reputation: 5549
  • View blog
  • Posts: 17,176
  • Joined: 25-December 09

Re: Reading A Binary .DAT file

Posted 17 July 2013 - 08:21 PM

Please post you Musicfile.h file. Please insure we have a complete program so we can compile and run your program.

Also did you read and understand post #4?

Quote

One ideia is... use of another type of file stream to open. except of ofstream or ifstream.

This is a C++ program and it is usually not a good idea to mix C-stdio functions with C++ streams. The C++ streams are the correct solution for this problem.

Jim

This post has been edited by jimblumberg: 17 July 2013 - 08:23 PM

Was This Post Helpful? 0
  • +
  • -

#7 unknown500   User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 30
  • Joined: 11-June 12

Re: Reading A Binary .DAT file

Posted 17 July 2013 - 08:31 PM

View Postdarknessx, on 16 July 2013 - 09:01 PM, said:

One ideia is... use of another type of file stream to open. except of ofstream or ifstream.

like this one
FILE* stream;
char* mode;

mode = "ab+"; //Append, Create, Open, Write at file last line (or character)

stream = fopen("Filename",mode);



and if you want to get some information into the file you can use fget
and if you want to put some information you use fput

at least after you make all your operations into the file you close the handler with fclose
fclose(stream);



so its a idea. and you can try this if you want.


Hi. Thanks for your help. I tried to go this route, but the program is still crashing when I try to read the file via the loadFile() function. Here is what my saveFile() & loadFile() functions look like now:
//Reads the file
void loadFile()
{
     FILE* stream;
     char* mode;
     mode = "r"; //Open in read mode
     stream = fopen("music_organizer.dat", mode);
     MusicFile song;
     fgets((char *)&song,sizeof(song), stream); //Read a music file from "music_organizer.dat"
     musicList.push_back(song); //Add the music file that was read in to the linked list musicList
     fclose(stream);
}

//Writes to the file
void saveFile(){
     
     FILE* stream;
     char* mode;
     mode = "a+"; //Open in append mode
     stream = fopen("music_organizer.dat", mode);
     
     
     list<MusicFile>::iterator musicFile;
      for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
      {
          fputs((char*)&musicFile, stream); //Write a musicFile to "music_organizer.dat"
      }
     
    fclose(stream);
   
}


Any idea on what I am doing wrong?
Was This Post Helpful? 0
  • +
  • -

#8 unknown500   User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 30
  • Joined: 11-June 12

Re: Reading A Binary .DAT file

Posted 17 July 2013 - 09:06 PM

View Postjimblumberg, on 17 July 2013 - 08:21 PM, said:

Please post you Musicfile.h file. Please insure we have a complete program so we can compile and run your program.

Also did you read and understand post #4?

Quote

One ideia is... use of another type of file stream to open. except of ofstream or ifstream.

This is a C++ program and it is usually not a good idea to mix C-stdio functions with C++ streams. The C++ streams are the correct solution for this problem.

Jim


O.k. I have updated my program to use the C++ streams (not ofstream/ifstream). Here is my complete program for compiling/running purposes:

MusicFile.h
/**
 *  MusicFile.h - Class DEFINITION for a music file.  This class will be
 *                 a single node in the linked list.
 *
 * Course: CS3330 Data Structures and Algorithms.
 * Instructor: Dr. Jack Davault
 */

//To ensure that this header file does not get included more than once
#ifndef MUSICFILE_H    
#define MUSICFILE_H

#include <string>

using namespace std;


 class MusicFile
{
      
 public:
        //Constructors
        
        //Default constructor
        MusicFile(); 
        
        //Copy constructor (defines actions to be performed when copying class objects)
        MusicFile(const MusicFile &musicFile); //& = pointer, reference to object (object's address)
        ~MusicFile();
      
      //Functions
      void setRecordNumber(const int recordNumber);
      int getRecordNumber() const;
      
      void setName(const string name);
      string getName() const;
      
      void setLength(const string length);
      string getLength() const;
      
      void setArtist(const string artist);
      string getArtist() const;
      
      void setAlbum(const string album);
      string getAlbum() const;
      
      void setGenre(const string genre);
      string getGenre() const;
      
      void setRating(const int rating);
      int getRating() const;
      
      void setNumberOfTimesPlayed(const int numberOfTimesPlayed);
      int getNumberOfTimesPlayed() const;
      
      void setFileName(const string fileName);
      string getFileName() const;
      
     
private:
        //Members
        int recordNumber;  //record number associated with this song entry
        string name;        //name of the song
        string length;      //playing time of song in mm:ss
        string artist;      //artist of the song
        string album;       //album containg the song
        string genre;       //genre of the song
        int rating;         //user's rating of song (1-5)
        int numberOfTimesPlayed; //the number of times the song has been played
        string fileName;       //full path to file (C:\Music\mysong.mp3)
         
};
#endif      


MusicFile.cpp
/**
 *  MusicFile.cpp - Class IMPLEMENTATION for a music file.  This class 
 *                 will be a single node in the linked list.
 *
 * Course: CS3330 Data Structures and Algorithms.
 * Instructor: Dr. Jack Davault
 */
#include "MusicFile.h"

//Constructor definitions

MusicFile::MusicFile()  //Access MusicFile class by typing MusicFile::
{
   // Currently does nothing ...
}

// Copy constructor
MusicFile::MusicFile(const MusicFile &musicFile)
{
   this->recordNumber = musicFile.recordNumber;
   this->name = musicFile.name;
   this->length = musicFile.length;
   this->artist = musicFile.artist;
   this->album = musicFile.album;
   this->genre = musicFile.genre;
   this->rating = musicFile.rating;
   this->numberOfTimesPlayed = musicFile.numberOfTimesPlayed;
   this->fileName = musicFile.fileName;
}

MusicFile::~MusicFile()
{
   // Currently does nothing ...
}


//Function definitions

void MusicFile::setRecordNumber(const int recordNumber)
{
   this->recordNumber = recordNumber;
}

int MusicFile::getRecordNumber() const
{
   return recordNumber;
}

void MusicFile::setName(const string name)
{
   this->name = name;
}

string MusicFile::getName() const
{
   return name;
}

void MusicFile::setLength(const string length)
{
   this->length = length;
}

string MusicFile::getLength() const
{
   return length;
}

void MusicFile::setArtist(const string artist)
{
   this->artist = artist;
}

string MusicFile::getArtist() const
{
   return artist;
}

void MusicFile::setAlbum(const string album)
{
   this->album = album;
}

string MusicFile::getAlbum() const
{
   return album;
}
void MusicFile::setGenre(const string genre)
{
   this->genre = genre;
}

string MusicFile::getGenre() const
{
   return genre;
}
void MusicFile::setRating(const int rating)
{
   this->rating = rating;
}

int MusicFile::getRating() const
{
   return rating;
}
void MusicFile::setNumberOfTimesPlayed(int numberOfTimesPlayed)
{
   this->numberOfTimesPlayed = numberOfTimesPlayed;
}

int MusicFile::getNumberOfTimesPlayed() const
{
   return numberOfTimesPlayed;
}
void MusicFile::setFileName(string fileName)
{
   this->fileName = fileName;
}

string MusicFile::getFileName() const
{
   return fileName;
}


MusicInventory.cpp
#include "MusicFile.h"
#include <list> //STL linked list
#include <iostream> //To use cin

using namespace std;

//Function declarations
void menu();
void addSong();
void deleteSong();
void modifySong();
void displaySong(MusicFile musicFile);
void searchForAlbum();
void displayMusicInventory();
int getTotalNumberOfSongs();
string getTotalPlayingTime();
void loadFile();
void saveFile();
   
//Member declarations
list <MusicFile> musicList; 
int recordNumber = 100;

/* Main function. Runs the program. 
*/
int main(){
   loadFile();
   menu();
   return 0;
}

/* 
 *  This function adds a song (music file) to the linked list.
 */
void addSong()
{
   MusicFile musicFile;
   string userInput;

   cout << endl << "** ADD MUSIC FILE TO INVENTORY **" << endl << endl;

   cout << "Song Name> ";
   getline(cin, userInput, '\n');
   musicFile.setName(userInput);

   cout << "Length in mm:ss format> ";
   getline(cin, userInput, '\n');
   
   musicFile.setLength(userInput);
   
   cout << "Artist> ";
   getline(cin, userInput, '\n');
   musicFile.setArtist(userInput);
   
   cout << "Album> ";
   getline(cin, userInput, '\n');
   musicFile.setAlbum(userInput);
   
   cout << "Genre> ";
   getline(cin, userInput, '\n');
   musicFile.setGenre(userInput);
   
   cout << "Rating (between 1 & 5)> ";
   getline(cin, userInput, '\n');
   while(!(atoi(userInput.c_str()) >= 1 && atoi(userInput.c_str())<=5)){
        cout << "Enter a number between 1 & 5" << endl;
        cout << "Rating (between 1 & 5)> ";
        getline(cin, userInput, '\n');
   
   }
   musicFile.setRating(atoi(userInput.c_str()));  //c_str to convert strng to c style null terminated string
                                                  //then atoi to convert string to int
   cout << "Number of times played> ";
   getline(cin, userInput, '\n');
   musicFile.setNumberOfTimesPlayed(atoi(userInput.c_str()));
   
   cout << "Complete path of music file (Ex. C:\\Music\\mysong.mp3)  > "; //Do 2 //'s to escape special / character
   getline(cin, userInput, '\n');
   musicFile.setFileName(userInput);
   
   musicFile.setRecordNumber(recordNumber);
   
   recordNumber = recordNumber + 1; //Increment record number by 1 for each song
   
   // Add to the linked list
   musicList.push_back(musicFile);

   return;
}


/* 
 * This function deletes a song from the linked list based on the given
 * record number.
 */
void deleteSong()
{
   string number;
   bool foundEntry = false;

   cout << endl << "** DELETE SONG FROM INVENTORY **" << endl << endl;
   cout << "Record Number> ";

   getline(cin, number, '\n');

   list<MusicFile>::iterator musicFile;
   for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
   {
      if (musicFile->getRecordNumber() == atoi(number.c_str()))
      {
        foundEntry = true;
        musicList.erase(musicFile);
      }
   }
                                                                             
   if (foundEntry)
      cout << "Entry deleted." << endl;
   else
      cout << "Entry not found." << endl;

   return;
}



/*
* This function displays all songs conatined in a given album.
*/
void searchForAlbum(){     
     string albumName;
     bool foundEntry = false;

     cout << endl << "** SEARCH FOR ALBUM **" << endl << endl;
     cout << "Album> ";

     getline(cin, albumName, '\n');

     list<MusicFile>::iterator musicFile;
      for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
     {
      if (musicFile->getAlbum() == albumName)
      {       
              foundEntry = true;
              displaySong(*musicFile); //Note: * to get musicFile object that we can use in displaySong
      }                                // * dereferences iterator object musicFile so we can go inside address & get object
     }
                                                                             
   if (!foundEntry){
      cout << "Entry not found." << endl;
   }
   return;    
}

/*
* This helper function displays a single song given a MusicFile object.
*/
void displaySong(MusicFile song){  //Note: * means pointer and pointers use -> instead of .
      cout << "Number:        " << song.getRecordNumber() << endl;
      cout << "Name:          " << song.getName() << endl;
      cout << "Length:        " << song.getLength() << endl;
      cout << "Artist:        " << song.getArtist() << endl;
      cout << "Album:         " << song.getAlbum() << endl;
      cout << "Genre:         " << song.getGenre() << endl;
      cout << "Rating:        " << song.getRating() << endl;
      cout << "Played Times:  " << song.getNumberOfTimesPlayed() << endl;
      cout << "Path to file:  " << song.getFileName() << endl;
      cout << "---------------------------------------------" << endl;
}



 /* 
 * This function displays all of the songs that are contained in the 
 * linked list.
 */
void displayMusicInventory()
{
   cout << endl << "** DISPLAY MUSIC INVENTORY **" << endl << endl;

   string prompt;

   list<MusicFile>::iterator musicFile;
  
   for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
   {
       displaySong(*musicFile);
     
   }
   
   //Display total # of songs & total playing time for all songs (hh:mm:ss)!
   cout << "Total # of Songs: " << getTotalNumberOfSongs() << endl;
   cout << "Total Time: " << getTotalPlayingTime() << endl;

   return;
}

/* 
 * This function provides the main menu for the user.
 */
void menu()
{
   string userOption;
   bool exitProgram = false;
  
   while (!exitProgram)
   {
      // Allow the user to select options to add, delete, modify, and 
      // list all data in the music list.
      cout << endl << "** MUSIC INVENTORY V1.1 MAIN MENU **" << endl << endl;
      cout << "   1. Add entry" << endl;
      cout << "   2. Delete entry" << endl;
      cout << "   3. Display entries" << endl;
      cout << "   4. Search for Album" << endl;
      cout << "   5. Modify a Song" << endl;
      cout << endl << "   99. Exit program" << endl << endl;
   
      cout << "Option> ";
      getline(cin, userOption, '\n');
   
      // Process user entry
      switch (atoi(userOption.c_str()))
      {
          case 1:
            addSong();
            break; 
   
          case 2:
            deleteSong();
            break; 

          case 3:
            displayMusicInventory();
            break; 
          
          case 4:
               searchForAlbum();
               break;
          case 5:
               modifySong();
               break;
          // Save address book and then exit program
          case 99:
               saveFile();
              exitProgram = true;
            break;

          default:
            cerr << "Error: unknown option!" << endl;
            break;
      }
   }

   return;    
}

/*Returns the total number of songs contained in the linked list musicList.
*/
int getTotalNumberOfSongs(){
     list<MusicFile>::iterator musicFile;
   int songCounter = 0; //Start songCounter @ 0
   for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
   {
       songCounter++;
       
   }
    return songCounter;
}

/*Returns the total playing time of all the songs in the linked list musicList as
a string in the format hh:mm:ss
*/
string getTotalPlayingTime(){
       string totalTime;
       int totalMinutes = 0;
       int totalSeconds = 0;
       
       list <MusicFile>:: iterator musicFile;
       for(musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile){
          string timeOfSong = musicFile->getLength();
          string delimiter = ":";
          string minutes = timeOfSong.substr(0, timeOfSong.find(delimiter));
          string seconds = timeOfSong.substr(timeOfSong.find(delimiter) + 1, timeOfSong.length());
          
       
            
          totalMinutes = totalMinutes + atoi(minutes.c_str());
          totalSeconds = totalSeconds + atoi(seconds.c_str());
       }
       
    
     char totalHoursBuffer [33];       //Memory to hold totalHours string
     char totalMinutesBuffer [33];       //Memory to hold totalMinutes string
     char totalSecondsBuffer [33];      //Memory to hold totalSeconds string
     
     /*Convert totalMinutes to string, store it in totalMinutesBuffer, and use 
     decimal - not binary or hex - numbers (10) */
     itoa(totalMinutes/60, totalHoursBuffer, 10); 
     itoa(totalMinutes % 60, totalMinutesBuffer, 10);   
     itoa(totalSeconds % 60, totalSecondsBuffer, 10);
     
     //Append hours, minutes, & seconds to totalTime string
     totalTime.append(totalHoursBuffer); 
     totalTime.append(":");
     totalTime.append(totalMinutesBuffer);
     totalTime.append(":");
     totalTime.append(totalSecondsBuffer);
               
     return totalTime;
}

/* This function modifies a single musicFile(song) in the linkedList musicList.
*/
void modifySong(){

string songName;
bool foundEntry = false;

cout << endl << "** MODIFY A SONG **" << endl << endl;
cout << "Name of Song to Modify> ";

getline(cin, songName, '\n');

list<MusicFile>::iterator musicFile;
for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
    {
      if (musicFile->getName() == songName)
      {       
              foundEntry = true;
              string userInput;

              cout << "Song Name> ";
              getline(cin,userInput,'\n');
              if(!userInput.empty()){
              musicFile->setName(userInput);
              }
              cout << "Length in mm:ss format> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setLength(userInput);
              }
              cout << "Artist> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setArtist(userInput);
              }
              cout << "Album> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setAlbum(userInput);
              }
              cout << "Genre> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setGenre(userInput);
              }
              cout << "Rating (between 1 & 5)> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setRating(atoi(userInput.c_str()));  //c_str to convert strng to c style null terminated string
              }                                    //then atoi to convert string to int
              cout << "Number of times played> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setNumberOfTimesPlayed(atoi(userInput.c_str()));
              }
              cout << "Complete path of music file (Ex. C:\\Music\\mysong.mp3)  > "; //Do 2 //'s to escape special / character
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setFileName(userInput);
              }
    }                                
     }
                                                                             
   if (foundEntry)
      cout << "Entry modified." << endl;
   else
      cout << "Entry not found." << endl;
   return;       
    
}

/*This function reads in all the musicFiles(songs) contained in
the file "music_organizer.dat".
*/
void loadFile()
{
     FILE* stream;
     char* mode;
     mode = "r"; //Open in read mode
     stream = fopen("music_organizer.dat", mode);
     MusicFile song;
     fgets((char *)&song,sizeof(song), stream);
     musicList.push_back(song);
     fclose(stream);
}

/*This function writes all the musicFiles(songs) currently in
the linked list musicList to the file "music_organizer.dat".
*/
void saveFile(){
     
     FILE* stream;
     char* mode;
     mode = "a+"; //Open in append mode
     stream = fopen("music_organizer.dat", mode);
     
     list<MusicFile>::iterator musicFile;
     for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
      {
          fputs((char*)&musicFile, stream);
      }
     
     fclose(stream);

}



View Post#define, on 17 July 2013 - 12:58 PM, said:

Hi, your MusicFile class contains strings, which are a basically like pointers to data in dynamic memory. When you save the class to file you are not saving the data. So it cannot be read.


Hi. Thanks for your help. How would I go about changing my MusicFile class to make it so that its data can be saved and then read? Would I have to change all the strings in my MusicFile.h & MusicFile.cpp classes to some other data type?

This post has been edited by unknown500: 17 July 2013 - 09:05 PM

Was This Post Helpful? 0
  • +
  • -

#9 jimblumberg   User is offline

  • member icon

Reputation: 5549
  • View blog
  • Posts: 17,176
  • Joined: 25-December 09

Re: Reading A Binary .DAT file

Posted 17 July 2013 - 10:17 PM

Quote

How would I go about changing my MusicFile class to make it so that its data can be saved and then read?

Writing std::strings using write has several problems. The first problem was already mentioned the other problem is that to use read and write you must know how many bytes to read and write, you either need to write/read a fixed number of bytes or somehow record the number of bytes written into the file.

Quote

Would I have to change all the strings in my MusicFile.h & MusicFile.cpp classes to some other data type?

Is there a reason you are trying to use write/read and binary files? I really recommend you use the formatted IO methods to a text file instead. This can be easily accomplished by overloading the extraction and insertion operators.


Quote

O.k. I have updated my program to use the C++ streams (not ofstream/ifstream).

What? The ofstream/ifstream classes are the C++ streams. The last item in my last post wasn't aimed at you but at darknessx who suggested using C-stdio functions.


Also there is a problem in the following snippet:
     ofstream my_file;
     my_file.open("music_organizer.dat", ios::binary);

     if(!my_file){
       //If file doesn't exist create it here
        ofstream my_file("music_organizer.dat", ios::binary);
     }


By default an ofstream opens the file erasing the contents of the file in the process. If the file doesn't exist it will create an empty file. So if the file didn't properly open the first time there is probably some kind of permission problem, and you should terminate the program after telling the user the file couldn't be opened. Also that second instance is only available in the if statement scope, at the closing brace of the if this instance is destroyed.

Also with the C++ streams remember that they have a destructor that is called when they go out of scope so you normally don't need to call the close() method. Just let them be closed by the destructor.


Jim

This post has been edited by jimblumberg: 17 July 2013 - 10:26 PM

Was This Post Helpful? 1
  • +
  • -

#10 unknown500   User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 30
  • Joined: 11-June 12

Re: Reading A Binary .DAT file

Posted 20 July 2013 - 10:32 AM

@jimblumberg

O.k. I have changed my code to use the C++ streams and the overloaded << and >> operators. (I got confused before as I am relatively new to C++.)

I am still having some trouble reading the file, though. For example, I have a line in the "music_organizer.dat" file that looks this:

Record Number: 100 Name: Hello Playing Time: 3:22 Artist: Me Album: You Genre: You & Me Rating: 4 Played Times : 10 File Name: Hello.mp3

But, when I try to read in that line, I get this result:

Record Number: 2293136 Name: Playing Time: Artist: Album: Genre: Rating: 2293272 Played Times : 4456909 File Name:

Do you know what I am doing wrong?

Here is my updated code for compiling/running purposes:

MusicFile.h
/**
 *  MusicFile.h - Class DEFINITION for a music file.  This class will be
 *                 a single node in the linked list.
 *
 * Course: CS3330 Data Structures and Algorithms.
 * Instructor: Dr. Jack Davault
 */

//To ensure that this header file does not get included more than once
#ifndef MUSICFILE_H    
#define MUSICFILE_H

#include <string>
#include <iostream>

using namespace std;


 class MusicFile
{
      
 public:
        //Constructors
        
        //Default constructor
        MusicFile(); 
        
        //Copy constructor (defines actions to be performed when copying class objects)
        MusicFile(const MusicFile &musicFile); //& = pointer, reference to object (object's address)
        ~MusicFile();
      
      //Functions
      
      //To overload << (cout) operator to write a musicFile
      friend ostream& operator << (ostream& os, const MusicFile& musicFile);
      
      //To overload >> (cin) operator to read a musicFile
      friend istream &operator>>( istream  &is, MusicFile &musicFile );
      
      void setRecordNumber(const int recordNumber);
      int getRecordNumber() const;
      
      void setName(const string name);
      string getName() const;
      
      void setLength(const string length);
      string getLength() const;
      
      void setArtist(const string artist);
      string getArtist() const;
      
      void setAlbum(const string album);
      string getAlbum() const;
      
      void setGenre(const string genre);
      string getGenre() const;
      
      void setRating(const int rating);
      int getRating() const;
      
      void setNumberOfTimesPlayed(const int numberOfTimesPlayed);
      int getNumberOfTimesPlayed() const;
      
      void setFileName(const string fileName);
      string getFileName() const;
      
     
private:
        //Members
        int recordNumber;  //record number associated with this song entry
        string name;        //name of the song
        string length;      //playing time of song in mm:ss
        string artist;      //artist of the song
        string album;       //album containg the song
        string genre;       //genre of the song
        int rating;         //user's rating of song (1-5)
        int numberOfTimesPlayed; //the number of times the song has been played
        string fileName;       //full path to file (C:\Music\mysong.mp3)
         
};
#endif      
      



MusicFile.cpp
/**
 *  MusicFile.cpp - Class IMPLEMENTATION for a book record.  This class 
 *                 will be a single node in the linked list.
 *
 * Course: CS3330 Data Structures and Algorithms.
 * Instructor: Dr. Jack Davault
 */
#include "MusicFile.h"

//Constructor definitions

MusicFile::MusicFile()  //Access MusicFile class by typing MusicFile::
{
   // Currently does nothing ...
}

// Copy constructor
MusicFile::MusicFile(const MusicFile &musicFile)
{
   this->recordNumber = musicFile.recordNumber;
   this->name = musicFile.name;
   this->length = musicFile.length;
   this->artist = musicFile.artist;
   this->album = musicFile.album;
   this->genre = musicFile.genre;
   this->rating = musicFile.rating;
   this->numberOfTimesPlayed = musicFile.numberOfTimesPlayed;
   this->fileName = musicFile.fileName;
}

MusicFile::~MusicFile()
{
   // Currently does nothing ...
}


//Function definitions

//To overload << (cout) to write a musicFile
 ostream& operator << (ostream& os, const MusicFile& musicFile){
      os << "Record Number: " << musicFile.recordNumber << 
      " Name: " << musicFile.name << " Playing Time: " << musicFile.length 
      << " Artist: " << musicFile.artist << " Album: " << musicFile.album
      << " Genre: " << musicFile.genre << " Rating: " << musicFile.rating
      << " Played Times : " << musicFile.numberOfTimesPlayed << " File Name: "
      << musicFile.fileName;
          
        
          return os;
 }
 
  //To overload >> (cin) operator to read a musicFile
 istream &operator>>( istream  &is, MusicFile &musicFile ){
   is >> musicFile.recordNumber >> musicFile.name >> musicFile.length >> 
   musicFile.artist >> musicFile.album >> musicFile.genre >> 
   musicFile.rating >> musicFile.numberOfTimesPlayed >> musicFile.fileName;
   
   return is;
   
  
 }



void MusicFile::setRecordNumber(const int recordNumber)
{
   this->recordNumber = recordNumber;
}

int MusicFile::getRecordNumber() const
{
   return recordNumber;
}

void MusicFile::setName(const string name)
{
   this->name = name;
}

string MusicFile::getName() const
{
   return name;
}

void MusicFile::setLength(const string length)
{
   this->length = length;
}

string MusicFile::getLength() const
{
   return length;
}

void MusicFile::setArtist(const string artist)
{
   this->artist = artist;
}

string MusicFile::getArtist() const
{
   return artist;
}

void MusicFile::setAlbum(const string album)
{
   this->album = album;
}

string MusicFile::getAlbum() const
{
   return album;
}
void MusicFile::setGenre(const string genre)
{
   this->genre = genre;
}

string MusicFile::getGenre() const
{
   return genre;
}
void MusicFile::setRating(const int rating)
{
   this->rating = rating;
}

int MusicFile::getRating() const
{
   return rating;
}
void MusicFile::setNumberOfTimesPlayed(int numberOfTimesPlayed)
{
   this->numberOfTimesPlayed = numberOfTimesPlayed;
}

int MusicFile::getNumberOfTimesPlayed() const
{
   return numberOfTimesPlayed;
}
void MusicFile::setFileName(string fileName)
{
   this->fileName = fileName;
}

string MusicFile::getFileName() const
{
   return fileName;
}




MusicInventory.cpp
#include "MusicFile.h"
#include <list> //STL linked list
#include <iostream> //To use cin
#include <fstream> //To read & write from files

using namespace std;

//Function declarations
void menu();
void addSong();
void deleteSong();
void modifySong();
void displaySong(MusicFile musicFile);
void searchForAlbum();
void displayMusicInventory();
int getTotalNumberOfSongs();
string getTotalPlayingTime();
int loadFile();
int saveFile();
   
//Member declarations
list <MusicFile> musicList; 
int recordNumber = 100;

/* Main function. Runs the program. 
*/
int main(){
    
   loadFile();
   menu();
   return 0;
}

/* 
 *  This function adds a song (music file) to the linked list.
 */
void addSong()
{
   MusicFile musicFile;
   string userInput;

   cout << endl << "** ADD MUSIC FILE TO INVENTORY **" << endl << endl;

   cout << "Song Name> ";
   getline(cin, userInput, '\n');
   musicFile.setName(userInput);

   cout << "Length in mm:ss format> ";
   getline(cin, userInput, '\n');
   
   musicFile.setLength(userInput);
   
   cout << "Artist> ";
   getline(cin, userInput, '\n');
   musicFile.setArtist(userInput);
   
   cout << "Album> ";
   getline(cin, userInput, '\n');
   musicFile.setAlbum(userInput);
   
   cout << "Genre> ";
   getline(cin, userInput, '\n');
   musicFile.setGenre(userInput);
   
   cout << "Rating (between 1 & 5)> ";
   getline(cin, userInput, '\n');
   while(!(atoi(userInput.c_str()) >= 1 && atoi(userInput.c_str())<=5)){
        cout << "Enter a number between 1 & 5" << endl;
        cout << "Rating (between 1 & 5)> ";
        getline(cin, userInput, '\n');
   
   }
   musicFile.setRating(atoi(userInput.c_str()));  //c_str to convert strng to c style null terminated string
                                                  //then atoi to convert string to int
   cout << "Number of times played> ";
   getline(cin, userInput, '\n');
   musicFile.setNumberOfTimesPlayed(atoi(userInput.c_str()));
   
   cout << "Complete path of music file (Ex. C:\\Music\\mysong.mp3)  > "; //Do 2 //'s to escape special / character
   getline(cin, userInput, '\n');
   musicFile.setFileName(userInput);
   
   musicFile.setRecordNumber(recordNumber);
   
   recordNumber = recordNumber + 1; //Increment record number by 1 for each song
   
   // Add to the linked list
   musicList.push_back(musicFile);

   return;
}


/* 
 * This function deletes a song from the linked list based on the given
 * record number.
 */
void deleteSong()
{
   string number;
   bool foundEntry = false;

   cout << endl << "** DELETE SONG FROM INVENTORY **" << endl << endl;
   cout << "Record Number> ";

   getline(cin, number, '\n');

   list<MusicFile>::iterator musicFile;
   for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
   {
      if (musicFile->getRecordNumber() == atoi(number.c_str()))
      {
        foundEntry = true;
        musicList.erase(musicFile);
      }
   }
                                                                             
   if (foundEntry)
      cout << "Entry deleted." << endl;
   else
      cout << "Entry not found." << endl;

   return;
}



/*
* This function displays all songs conatined in a given album.
*/
void searchForAlbum(){     
     string albumName;
     bool foundEntry = false;

     cout << endl << "** SEARCH FOR ALBUM **" << endl << endl;
     cout << "Album> ";

     getline(cin, albumName, '\n');

     list<MusicFile>::iterator musicFile;
      for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
     {
      if (musicFile->getAlbum() == albumName)
      {       
              foundEntry = true;
              displaySong(*musicFile); //Note: * to get musicFile object that we can use in displaySong
      }                                // * dereferences iterator object musicFile so we can go inside address & get object
     }
                                                                             
   if (!foundEntry){
      cout << "Entry not found." << endl;
   }
   return;    
}

/*
* This helper function displays a single song given a MusicFile object.
*/
void displaySong(MusicFile song){  //Note: * means pointer and pointers use -> instead of .
      cout << "Number:        " << song.getRecordNumber() << endl;
      cout << "Name:          " << song.getName() << endl;
      cout << "Length:        " << song.getLength() << endl;
      cout << "Artist:        " << song.getArtist() << endl;
      cout << "Album:         " << song.getAlbum() << endl;
      cout << "Genre:         " << song.getGenre() << endl;
      cout << "Rating:        " << song.getRating() << endl;
      cout << "Played Times:  " << song.getNumberOfTimesPlayed() << endl;
      cout << "Path to file:  " << song.getFileName() << endl;
      cout << "---------------------------------------------" << endl;
}



 /* 
 * This function displays all of the songs that are contained in the 
 * linked list.
 */
void displayMusicInventory()
{
   cout << endl << "** DISPLAY MUSIC INVENTORY **" << endl << endl;

   string prompt;

   list<MusicFile>::iterator musicFile;
  
   for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
   {
       displaySong(*musicFile);
     
   }
   
   //Display total # of songs & total playing time for all songs (hh:mm:ss)!
   cout << "Total # of Songs: " << getTotalNumberOfSongs() << endl;
   cout << "Total Time: " << getTotalPlayingTime() << endl;

   return;
}

/* 
 * This function provides the main menu for the user.
 */
void menu()
{
   string userOption;
   bool exitProgram = false;
  
   while (!exitProgram)
   {
      // Allow the user to select options to add, delete, modify, and 
      // list all data in the music list.
      cout << endl << "** MUSIC INVENTORY V1.1 MAIN MENU **" << endl << endl;
      cout << "   1. Add entry" << endl;
      cout << "   2. Delete entry" << endl;
      cout << "   3. Display entries" << endl;
      cout << "   4. Search for Album" << endl;
      cout << "   5. Modify a Song" << endl;
      cout << endl << "   99. Exit program" << endl << endl;
   
      cout << "Option> ";
      getline(cin, userOption, '\n');
   
      // Process user entry
      switch (atoi(userOption.c_str()))
      {
          case 1:
            addSong();
            break; 
   
          case 2:
            deleteSong();
            break; 

          case 3:
            displayMusicInventory();
            break; 
          
          case 4:
               searchForAlbum();
               break;
          case 5:
               modifySong();
               break;
          // Save address book and then exit program
          case 99:
               saveFile();
              exitProgram = true;
            break;

          default:
            cerr << "Error: unknown option!" << endl;
            break;
      }
   }

   return;    
}

/*Returns the total number of songs contained in the linked list musicList.
*/
int getTotalNumberOfSongs(){
     list<MusicFile>::iterator musicFile;
   int songCounter = 0; //Start songCounter @ 0
   for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
   {
       songCounter++;
       
   }
    return songCounter;
}

/*Returns the total playing time of all the songs in the linked list musicList as
a string in the format hh:mm:ss
*/
string getTotalPlayingTime(){
       string totalTime;
       int totalMinutes = 0;
       int totalSeconds = 0;
       
       list <MusicFile>:: iterator musicFile;
       for(musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile){
          string timeOfSong = musicFile->getLength();
          string delimiter = ":";
          string minutes = timeOfSong.substr(0, timeOfSong.find(delimiter));
          string seconds = timeOfSong.substr(timeOfSong.find(delimiter) + 1, timeOfSong.length());
          
       
            
          totalMinutes = totalMinutes + atoi(minutes.c_str());
          totalSeconds = totalSeconds + atoi(seconds.c_str());
       }
       
    
     char totalHoursBuffer [33];       //Memory to hold totalHours string
     char totalMinutesBuffer [33];       //Memory to hold totalMinutes string
     char totalSecondsBuffer [33];      //Memory to hold totalSeconds string
     
     /*Convert totalMinutes to string, store it in totalMinutesBuffer, and use 
     decimal - not binary or hex - numbers (10) */
     itoa(totalMinutes/60, totalHoursBuffer, 10); 
     itoa(totalMinutes % 60, totalMinutesBuffer, 10);   
     itoa(totalSeconds % 60, totalSecondsBuffer, 10);
     
     //Append hours, minutes, & seconds to totalTime string
     totalTime.append(totalHoursBuffer); 
     totalTime.append(":");
     totalTime.append(totalMinutesBuffer);
     totalTime.append(":");
     totalTime.append(totalSecondsBuffer);
               
     return totalTime;
}

/* This function modifies a single musicFile(song) in the linkedList musicList.
*/
void modifySong(){

string songName;
bool foundEntry = false;

cout << endl << "** MODIFY A SONG **" << endl << endl;
cout << "Name of Song to Modify> ";

getline(cin, songName, '\n');

list<MusicFile>::iterator musicFile;
for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
    {
      if (musicFile->getName() == songName)
      {       
              foundEntry = true;
              string userInput;

              cout << "Song Name> ";
              getline(cin,userInput,'\n');
              if(!userInput.empty()){
              musicFile->setName(userInput);
              }
              cout << "Length in mm:ss format> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setLength(userInput);
              }
              cout << "Artist> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setArtist(userInput);
              }
              cout << "Album> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setAlbum(userInput);
              }
              cout << "Genre> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setGenre(userInput);
              }
              cout << "Rating (between 1 & 5)> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setRating(atoi(userInput.c_str()));  //c_str to convert strng to c style null terminated string
              }                                    //then atoi to convert string to int
              cout << "Number of times played> ";
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setNumberOfTimesPlayed(atoi(userInput.c_str()));
              }
              cout << "Complete path of music file (Ex. C:\\Music\\mysong.mp3)  > "; //Do 2 //'s to escape special / character
              getline(cin, userInput, '\n');
              if(!userInput.empty()){
              musicFile->setFileName(userInput);
              }
    }                                
     }
                                                                             
   if (foundEntry)
      cout << "Entry modified." << endl;
   else
      cout << "Entry not found." << endl;
   return;       
    
}

/*This function reads in all the musicFiles(songs) contained in
the file "music_organizer.dat".
*/
int loadFile()
{
    ifstream my_file;
    my_file.open("music_organizer.dat");
    
    //Return an error code if file cannot be opened
    if(!my_file){
         return -1;
    }
    
  
    MusicFile song;
    my_file >> song; //Reads in one musicFile from the file
    musicList.push_back(song);
    
    
    return 0;
    
}

/*This function writes all the musicFiles(songs) currently in
the linked list musicList to the file "music_organizer.dat".
*/
int saveFile(){
     ofstream my_file;
     my_file.open("music_organizer.dat", ofstream::app); //Open file in append(not overwrite mode)
     
     //Return an errror code if file cannot be opened
     if(!my_file){
        return -1;
     }
     //Write every musicFile in the musicList to the file
     list<MusicFile>::iterator musicFile;
     for (musicFile = musicList.begin(); musicFile != musicList.end(); ++musicFile)
      {
          my_file << *musicFile;
      }
    
     return 0;

}


Was This Post Helpful? 0
  • +
  • -

#11 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6400
  • View blog
  • Posts: 21,954
  • Joined: 05-May 12

Re: Reading A Binary .DAT file

Posted 20 July 2013 - 10:51 AM

The problem is that your << output format doesn't match your >> input format. Your output has field name strings, while your input assumes that the field names do not exist. For example, you output "Record number: 12", but when you try to read in you just have is >> musicFile.recordNumber. The runtime is trying to parse the text string "Record" as an integer which fails.
Was This Post Helpful? 0
  • +
  • -

#12 unknown500   User is offline

  • New D.I.C Head

Reputation: 3
  • View blog
  • Posts: 30
  • Joined: 11-June 12

Re: Reading A Binary .DAT file

Posted 20 July 2013 - 11:36 AM

View PostSkydiver, on 20 July 2013 - 10:51 AM, said:

The problem is that your << output format doesn't match your >> input format. Your output has field name strings, while your input assumes that the field names do not exist. For example, you output "Record number: 12", but when you try to read in you just have is >> musicFile.recordNumber. The runtime is trying to parse the text string "Record" as an integer which fails.


O.k. How would I go about fixing this? Should I remove my field names from my output? Or is there a way to make my input not read in the field names? Thanks for your help.
Was This Post Helpful? 0
  • +
  • -

#13 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 6400
  • View blog
  • Posts: 21,954
  • Joined: 05-May 12

Re: Reading A Binary .DAT file

Posted 20 July 2013 - 03:34 PM

The most expedient way is to read the field names into dummy variables. The truly correct way is to parse the input and ensure that you are "in sync" with the fields that you were expecting to be reading.
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1