C ++:文件处理对象和文件的操作+二进制文件未读取

时间:2013-01-26 18:46:59

标签: c++ file-handling

我一直在使用Turbo C ++(:/)并遇到了问题。

我正在制作一个需要文件处理的学校项目。我的程序接受用户的输入并给出4个选项:

  1. 覆盖/修改现有文件
  2. 创建文件
  3. 删除文件
  4. 查看所有文件
  5. CLASS DEFINITION:

    #define max 20
    class playlist{
        static int ctr;
        int sr;
        char name[max];
        class favsong
        {
    
            char song[max];
            char genre[max];
            char artist[max];
            int rating;
    
        public:
            void playin()
            {
                cout<<"Enter song name"<<endl;
                gets(song);
                cout<<"Enter genre"<<endl;
                gets(genre);
                cout<<"Enter artist"<<endl;
                gets(artist);
    
    
                cout<<"Enter rating (out of 5)"<<endl;
                cin>>rating;
    
            }
            void playout()
            {
                cout<<"\nSong:";
                puts(song);
                cout<<"Artist:";
                puts(artist);
                cout<<"Genre:";
                puts(genre);
                cout<<"rating:"<<rating<<endl;
            }
            favsong()
            {
                rating=0;
                strcpy(song,"Not Assigned");
                strcpy(genre,"Not Assigned");
                strcpy(artist,"Not Assigned");
            }
            ~favsong(){}
        }favs[5];
    
    public:
        void input();
        void output();
    
        void showname()
        {
            puts(name);
        }
    
        int givesr()
        {
            return sr;
        }
    
        int existp (int n)
        {
            if(n==sr)
                return 1;
            else
                return 0;
        }
    
        playlist()//constructor
        {
            strcpy(name,"Default playlist");
            sr=ctr;
            ctr++;
        }
    
        ~playlist(){}
    
        int existp(char arr[])
        {
            if(strcmp(name,arr)==0)
                return 1;
            else
                return 0;
        }
    
    }wmp[max],obj;
    int playlist::ctr=1;
    
    void playlist::input()
    {
        cout<<"Enter playlist name"<<endl;
        gets(name);
        for(int i=0;i<5;i++)
            favs[i].playin();
        cout<<"Input complete"<<endl;
    
    }
    
    void playlist::output()
    {
        cout<<"Playlist no"<<sr;
        for(int i=0;i<5;i++)
            favs[i].playout();
        cout<<"\noutput complete"<<endl;
    }
    

    当我尝试创建播放列表时,我正在遇到运行时错误: 代码:

    case 2: cout<<"Creating new playlist...press enter to continue"<<endl;
    getch();
    obj.input();
    h=0;
    while(!file.eof()){
        fileo.read((char*)&wmp[h],sizeof(wmp));
        if(wmp[h].existp("Default playlist")){ //int existp(int*a) compares the object's
                                               // name to the string"Default Playlist
            pos=fileo.tellg();
            file.seekp(-pos,ios::cur);
            file.write((char*)&wmp,sizeof(wmp) );
        }
        h++;
    }
    break;
    

    我已经在这3天了。这看起来很简单,但我不知道这里有什么问题。

    此外,每次运行后文件都会被擦除: 代码:

    ofstream file("playlist.dat",ios::out|ios::app|ios::noreplace|ios::binary|ios::ate);
    ifstream fileo("playlist.dat",ios::in|ios::binary);
    

    ------------- ----------- EDIT

    我将班级成员的WhozCraig和qPCR4vir的建议和单独的函数用于将自己插入到文件中。事情是我再次陷入障碍.. 输出显示所有数据成员,而它应该只显示sr no。和播放列表名称。我认为输入或输出是错误的。 代码:

    void existp()  //function to show all existing playlists in the file.
                {  ifstream tmp("playlist.dat",ios::in|ios::binary);
                    tmp.seekg(ios::beg);
                    tmp.read((char*)&wmp,sizeof(wmp));
                    for(int i=0;i<max;i++){
                    cout<<wmp[i].givesr();
                    wmp[i].showname();
               }
               tmp.close();
                }
    
    
        void fileput(){  //fileput and fileget are functions to put inner class member in //file
        ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
        file<<song<<endl<<artist<<endl<<genre<<endl<<rating<<endl;
    file.close();
                }
    
    void fileget(){
    ifstream file("Playlist.dat",ios::in|ios::binary);
    file.getline(song,max,'\n');
        file.getline(artist,max,'\n');
    file.getline(genre,max,'\n');
    file>>rating;
    file.close();
            }
    

    //将外部类数据成员放在文件

    中的外部类函数的函数定义
    void playput(long int pos){
    ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
    file.seekp(pos,ios::beg);
    file<<name<<"\n";
    for(int i=0;i<5;i++)
    favs[i].fileput();
    file.close();
    }
    
    void playget(long int pos){
    ifstream file("Playlist.dat",ios::in|ios::binary);
    file.seekg(pos,ios::beg);
    file.getline(name,max,'\n');
    for(int i=0;i<5;i++)
    favs[i].fileget();
    file.close();
         }
    

    -------------编辑2 ------------- 终于完成了!输入,输出,删除都很顺利。只有一个小问题是'sr'是取内存值而不是序列号。来自文件的值。因此,不是将第二个播放列表打印为2.Second播放列表,而是打印2609.Second Playlist。

    谢谢你们,大家好。 我真的很感激,你认真帮助了我很多! @WhozCraig和@qPCRvir:谢谢大家,感谢您的回答和建议。我真的很感激。 :)

2 个答案:

答案 0 :(得分:2)

此代码存在多个问题,您可以考虑退回并重新考虑您真正想要做的事情。

对于初学者来说,循环读取逻辑在其项目读取大小方面存在根本缺陷。您应该每次迭代读取一个项目,或者只读取整个数组一次,然后枚举数组以查找可用于新播放列表的项目。问题的核心是:

fileo.read((char*)&wmp[h],sizeof(wmp));

这会从当前文件位置开始读取项目的大小,直至整个 wmp 数组的大小,并将结果存储在内存中的位置h数组中的wmp元素存在(wmp+h)。我真诚地希望您看到,如果h 永远大于0,这可能会读取过去数组的末尾并进入未定义的行为。

如果这是唯一改变的,那就应该这样做:

fileo.read((char*)&wmp[h],sizeof(wmp[h]));

但这只是冰山一角。循环本身存在根本缺陷,因为您也有固定的固定文件大小。从磁盘读取播放列表数组(或写入磁盘)没有理由进行迭代循环。只需批量写入整个数组,例如

ofstream ofs(filename, ios::out|ios::binary|ios::trunc);
ofs.write((char*)&wmp, sizeof(wmp));
ofs.close();

并以类似的偏见阅读:

ifstream ifs(filename, ios::in|ios::binary)
ifs.read((char*)&wmp, sizeof(wmp));
ifs.close();

但老实说,正确的方法是 以上。例如,将播放列表写入磁盘的正确方法是:

  1. 编写playlist::favorite类的成员函数,给定二进制流对象,可以将本身写入该输出流。
  2. 编写playlist类的成员函数,给定二进制流对象,可以编写本身,以及当前最喜欢的歌曲数,然后每个< / em>最喜欢的歌曲使用上面(1)中的喜欢 - 作家成员函数。
  3. 编写一个知道如何以二进制输出模式打开文件(给定名称)的全局函数,写出占用的播放列表条目的数量,然后为每个占用的条目调用播放列表上述(2)中的作者成员函数。
  4. 类似的逻辑将用于读取文件。

    1. 编写playlist::favorite的成员函数,给定输入二进制流对象引用,可以从流中读取本身
    2. 写一个playlist的成员函数,给定一个输入二进制流对象引用,可以自己读取,以及它最喜欢的数量,然后对于每个收藏,调用上面(1)中的收藏读者
    3. 编写一个知道如何打开输入二进制文件流对象的全局函数,然后读取其播放列表计数,然后为每个播放列表调用上面(2)中编写的播放列表阅读器。
    4. 这是做到这一点的众多方法中的一种,但是相当合乎逻辑且很好地链接。考虑一下。即便如此,也存在平台可移植性问题,但除非您将播放列表文件从一个平台共享到另一个平台,否则不应将其视为一个问题。

答案 1 :(得分:0)

我不想触及另一个答案,而现在我们还有其他问题而且我可以把所有问题搞得一团糟。我不能说,这不是完整的代码,只是一种更好的方式让我试图解释这些想法。

#include <iostream> 
#include <fstream> 
using namespace std;

#define max 20

class playlist
{   static int ctr;
    int sr;
    char name[max];
    class favsong
    {   char song[max];
        char genre[max];
        char artist[max];
        int rating;
      public:
        void playin()
        {   cout<<"Enter song name"<<endl;            gets(song);
            cout<<"Enter genre"<<endl;                gets(genre);
            cout<<"Enter artist"<<endl;               gets(artist);
            cout<<"Enter rating (out of 5)"<<endl;    cin>>rating;
        }
        void playout()
        {   cout<<"\nSong:";            puts(song);
            cout<<"Artist:";            puts(artist);
            cout<<"Genre:";             puts(genre);
            cout<<"rating:"         <<rating    <<endl;
        }
        void fileput(ofstream &file)   //  (Point 1:) put (get) inner class member (favsong) in file
        {   // txt variant  
            file<<song<<endl<<artist<<endl<<genre<<endl<<rating<<endl;
            // or the pure binary variant:
            //file.write ((char*)this, sizeof(favsong));
        }
        void fileput()   //  put (get) inner class member (favsong) in file
        {   ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
            file<<song<<endl<<artist<<endl<<genre<<endl<<rating<<endl;
            file.close();
        }
        void fileget(ifstream &file)
        {   // txt variant
            file.getline(song,  max,'\n');
            file.getline(artist,max,'\n');
            file.getline(genre, max,'\n');
            file>>rating;
        }
        void fileget()
        {
            ifstream file("Playlist.dat",ios::in|ios::binary);
            file.getline(song,  max,'\n');  
            file.getline(artist,max,'\n');
            file.getline(genre, max,'\n');
            file>>rating;
            file.close();
        }
        favsong()
        {   rating=0;
            strcpy(song,  "Not Assigned");
            strcpy(genre, "Not Assigned");
            strcpy(artist,"Not Assigned");
        }
        ~favsong(){}
    }favs[5];

 public:
    void input();
    void output();
    void playput(ofstream &file)        //  (Point 2:) puts outer class data members in file
    {
        // txt
        file<<name<<"\n";
        // or one "pure" binary variant
        //file.write (name, sizeof(name));

        for(int i=0;i<5;i++)
            favs[i].fileput(file);  // equal for both bin or txt

        // or one pure binary variant to put the entery list at once:
        //file.write ((char*)this, sizeof(playlist));
    }
    void playput( ofstream &file, long int pos)     //puts outer class data members in file
    {
        file.seekp(pos,ios::beg);
        playput(file);              // equal for both bin or txt
    }
    void playput(long int pos)      //puts outer class data members in file
    {
        ofstream file("Playlist.dat",ios::out|ios::app|ios::nocreate|ios::binary);
        file.seekp(pos,ios::beg);
        playput(file);
        file.close();
    }

    // now write the equivalent for get.....
    void playget(long int pos)
    {
        ifstream file("Playlist.dat",ios::in|ios::binary);
        file.seekg(pos,ios::beg);
        file.getline(name,max,'\n');
        for(int i=0;i<5;i++)
        favs[i].fileget(file);
        file.close();
     }
    void showname()     {        puts(name);    }
    int givesr()        {        return sr;     }
    int existp (int n)  {        return (n==sr) ?   1 : 0;    }

    playlist()//constructor
    {   strcpy(name,"Default playlist");
        sr=ctr;
        ctr++;
    }
    ~playlist(){}
    int existp(char arr[])  {    return (strcmp(name,arr)==0)  ?   1 : 0;    }

}wmp[max],obj;

int playlist::ctr=1;

void playlist::input()
{   cout<<"Enter playlist name"<<endl;
    gets(name);
    for(int i=0;i<5;i++)
        favs[i].playin();
    cout<<"Input complete"<<endl;
}

void playlist::output()
{   cout<<"Playlist no"<<sr;
    for(int i=0;i<5;i++)
        favs[i].playout();
    cout<<"\noutput complete"<<endl;
}

void existp()  //function to show all existing playlists in the file.
{  ifstream tmp("playlist.dat",ios::in|ios::binary);
    tmp.seekg(ios::beg);
    tmp.read((char*)&wmp,sizeof(wmp));
    for(int i=0;i<max;i++)
    {   cout<<wmp[i].givesr();
        wmp[i].showname();
    }
    tmp.close();
}
void save_playlist(const char *file_name)  //    (Point 3:)
{   ofstream file(file_name,ios::out|ios::binary);
    for(int i=0;i<max;i++)
        wmp[i].playput (file);

    // or one pure binary variant to put all list at once:
    //file.write((char*)&wmp,sizeof(wmp));

    file.close();
}
void load_playlist(const char *file_name)  //    (Point 3:)
{   ifstream file(file_name,ios::in|ios::binary);
    file.seekg(ios::beg);
    for(int i=0;i<max;i++)
        wmp[i].playget(file);

    // or one pure binary variant to get all list at once:
    //file.read((char*)&wmp,sizeof(wmp));

    file.close();
}

现在,操纵列表......

void using_play_list (const char *file_name)
{
    /*case 2:*/ cout<<"Creating new playlist...press enter to continue"<<endl;
    getch();
    obj.input();

    load_playlist(file_name);

    // now test and modify wmp as need.

    int h=0;
    while(h<max){
        if(wmp[h].existp("Default playlist"))
        {   //int existp(int*a) compares the object's
            // name to the string"Default Playlist
            //    ????????????
        }
        h++;
    }

    save_playlist(file_name);


    break;
}

这是@WhozCraig的所有想法,只是为了使代码更简单,而不是解决你的最终问题。