简体   繁体   中英

Loading from file cpp

I want to load a playlist from a textfile. The text file consists of albums with their songs, the first line is the album name, the second line is the number of songs in the album, then one song with data on each line until the album is finished, then the album name of the next album etc. To make things more fun, the list is it's own class, the album it's own class and the songs their own class. Here is an example of what the file can look like

Album name1

2

song1|artist1|234

song2|artist1|443

Album name2

3

song3|artist2|320

song4|artist2|360

song5|artist2|340

My problem is that when I load, the first album will be loaded correctly, but the second album (and third etc) will not have the full name loaded, it will miss the first character. So Album name2 would be loaded as lbum name2.

This is the classes involved with the functions and overloads that are used in doing this:

#ifndef DT019G_JUKEBOX_H
#define DT019G_JUKEBOX_H

#include "Prototypes.h"
#include "Album.h"
#include "Menu.h"

class Jukebox {
private:
    std::vector <Album> albums;
    Menu mainMenu, fileMenu, printMenu;

public:
    Jukebox() {
    void openFile();


void Jukebox::openFile() {
    Album tmpAlbum;
    std::fstream inFile(directory+fileName, std::ios::in);
      while(!inFile.eof()) {inFile>> tmpAlbum;
    albums.push_back(tmpAlbum);}
    inFile.close();
}


#ifndef DT019G_ALBUM_H
#define DT019G_ALBUM_H

#include "Prototypes.h"
#include "Song.h"
class Album {
public:
    std::string albumName;
private:
    std::vector <Song> songList;
public:
    Album() {albumName="NoName";}
    Album(std::string pName) {albumName=pName;}

    //Set/Get functions
    void setAlbumName (const std::string pname) {albumName=pname;}
    void setSongList (const std::vector <Song> pSongList) {songList=pSongList;}
    void clearSongList () {songList.clear();}

    // Add a song to the albums song list
    void addSongToAlbum (const Song pSong);

};

std::istream &operator>>(std::istream &is, Album &album);
#endif //DT019G_ALBUM_H

// Overloads the >> stream so it can be used to load an album from file.
// First it puts all the input in the vector inputData. Then when the first row (containing the album name)
// has been loaded into albumName, the first two entries of inputData are erased (the ones containing the album name and
// number of songs. Then only songs are left in vector thus they can be loaded into the songList with ease.
std::istream &operator>>(std::istream &is, Album &album){
    album.clearSongList();
    std::string tempData;
    std::getline(is, tempData);
    album.setAlbumName(tempData);
    std::getline(is, tempData);
    int numberOfSongs;
    std::istringstream iss(tempData);
    iss >> numberOfSongs;
    Song tempSong;
    for (size_t i=0; i<numberOfSongs; i++){
       std::getline(is, tempData);
       std::istringstream iss(tempData);
       iss>>tempSong;
       album.addSongToAlbum(tempSong);
    }
    is.get();
    return is;
}

I add the song class here eventhough I don't think it's necessary as it seems to function as intended

class Song {
private:
    string title;
    string artist;
    Time length;
public:
    // Default constructor
    Song() {title="noTitle"; artist="noArtist"; length=Time(0,0,0);}
    // Constructor using parameters
    Song (string pTitle, string pArtist, int pHours, int pMinutes, int pSeconds)
    {title=pTitle, artist=pArtist, length=Time(pHours, pMinutes, pSeconds);}

    // Set/Get functions
    void setTitle (string pTitle) {title=pTitle;}
    void setArtist (string pArtist) {artist=pArtist;}
    void setLength (Time pTime) {length=pTime;}
    string getTitle ()const {return title;}
    string getArtist ()const {return artist;}
    Time getLength () const {return length;}

    void clientProgram();
};

// Takes an in stream on the format title | artist | time and convert it to a Song object.
std::istream &operator>>(std::istream &is, Song &song);

#endif //DT019G_SONG_H

std::istream &operator>>(std::istream &is, Song &song){
    string loadData;
    std::getline(is, loadData);
    string tempSeconds;
    Time tempTime;
    size_t j,k,l;
    j=loadData.find(DELIM);
    k=loadData.find(DELIM, j+1);
    l=loadData.size();
    song.setTitle(loadData.substr(0,j));
    song.setArtist(loadData.substr(j+1,k-(j+1)));
    tempSeconds=loadData.substr(k+1, l-(k+1));
    std::istringstream iss(tempSeconds);
    iss >>tempTime;
    song.setLength(tempTime);
    is.get();
    return is;
}

Thanks for any help. I just can't find the reason for this to happen myself.

In your function

std::istream &operator>>(std::istream &is, Album &album){
    album.clearSongList();
    std::string tempData;
    std::getline(is, tempData);
    album.setAlbumName(tempData);
    std::getline(is, tempData);
    int numberOfSongs;
    std::istringstream iss(tempData);
    iss >> numberOfSongs;
    Song tempSong;
    for (size_t i=0; i<numberOfSongs; i++){
       std::getline(is, tempData);
       std::istringstream iss(tempData);
       iss>>tempSong;
       album.addSongToAlbum(tempSong);
    }
    is.get();
    return is;
}

std::getline() will consume newline characters and the final is.get() will consume the next character from the stream. It seems what is consumed here is the first character of the title of the next album.

To avoid this, you should remove this extra is.get(); .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM