【问题标题】:C++ : file handling_manipulation of objects anf filesr + binary file not readC ++:对象和文件的文件处理操作+未读取的二进制文件
【发布时间】:2013-01-10 12:13:04
【问题描述】:

我使用 Turbo C++ (:/) 有一段时间了,遇到了一个问题。

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

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

类定义:

#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);

-------------编辑-----------

我接受了 WhozCraig 和 qPCR4vir 的建议,并为班级成员提供了单独的功能将自己插入文件中。事情是我又遇到了路障.. 输出显示所有数据成员,而它应该只显示 sr 编号。和播放列表名称。我认为输入或输出是错误的。 代码:

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 Playlist,而是打印 2609.Second Playlist。

谢谢你们,你们所有人。 我真的很感激,你真的帮了我很多! @WhozCraig 和@qPCRvir:谢谢你们的回答和建议。我真的很感激。 :)

【问题讨论】:

  • wmp 是如何声明的?是 char 数组还是 char 数组的数组?
  • 我正在尝试将&amp;wmp[h],sizeof(wmp) 作为文件读取的最后两个参数正确的情况。我可以看到阅读到 wmp+h,sizeof(*wmp).. 或 &amp;wmp[h],sizeof(wmp[h]) 等,但不是当前代码中的内容。
  • @Antares 你能发一下这个类看起来像吗?类的标头声明可能就足够了。 (注意:请在问题中发布;添加代码时不要在此处作为评论)。
  • @simonc:谢谢。我不知道。

标签: c++ file-handling


【解决方案1】:

此代码存在多个问题,以至于您可能会考虑退后一步,重新考虑您真正想做的事情。

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

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

这会读取一个项目直到整个大小wmp数组从当前文件位置开始,将结果存储在内存中@ wmp 数组中的第 987654323@th 个元素存在 (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类的成员函数,给定一个二进制流对象,可以写它自己,以及它当前最喜欢的歌曲数量,然后每个 使用上述 (1) 中的 favorite-writer 成员函数最喜欢的歌曲。
  3. 编写一个全局函数,知道如何以二进制输出模式打开文件(给定名称),写出占用播放列表条目的数量,然后为每个占用的条目调用播放列表- 上述 (2) 中的 writer 成员函数。

类似的逻辑将用于读取文件。

  1. 编写playlist::favorite 的成员函数,在给定输入二进制流对象引用的情况下,它可以从流中读取自身
  2. 编写一个playlist 的成员函数,给定一个输入二进制流对象引用,它可以读取自身以及它的收藏计数,然后对于每个收藏,调用上面(1)中的收藏阅读器。
  3. 编写一个知道如何打开输入二进制文件流对象的全局函数,然后读取其播放列表计数,然后为每个播放列表调用上面 (2) 中编写的播放列表读取器。

只是执行此操作的众多方法之一,但相当合乎逻辑,并且链接得很好。考虑一下。即使这样,也存在平台可移植性问题,但除非您将播放列表文件从一个平台共享到另一个平台,否则这不应该成为问题。

【讨论】:

  • +1 除其他外,这是他的循环的 关键问题。其余的逻辑,以及.eof() 条件检查是其他的,以及整个查找时不断重写。
  • @WhozCraig。是的... Ì正在努力。你能写更多吗(抱歉,现在我妻子想看电影:-))现在我看到你在 2 小时前的评论中有这个答案......
  • @WhozCraig :谢谢...但是,不,不!我的意思是,在一个新的答案中!你的!请!
  • 呃。你的就在这里!我想你想让我把它充实一点=P。向可怜的家伙发送垃圾邮件毫无意义。我想他会明白基本的想法。
  • 电影结束了。 《声望》,很有意思。但在这里我也有一个有趣的情况。我想在答案中添加注释:感谢@WhozCraig,请不要投票。但我意识到,然后 WhozCraig,您的编辑签名将会丢失。我希望所有人都能理解,会阅读,但不要投票。谢谢!
【解决方案2】:

我不想触及其他答案,而现在我们还有其他问题,我不能乱来。我无法调试,这不是完整的代码,只是我试图解释这些想法的更好方法。

#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 的想法,只是为了让代码更简单,而不是为了解决你的最终问题。

【讨论】:

  • 但我必须在文件中的任何位置输入,具体取决于播放列表是否具有“默认播放列表”作为其名称。 save_playlist 和 load_playlist 不会那样做,对吧?
  • 当然,您可以尝试直接对文件执行此操作(使用获取 pos 的函数),但您会发现它不是很简单。这里的想法是“在内存中”、在 wmp 中执行此操作,然后重写输入文件。
  • 说实话,我并不确切知道 Turbo C++ 的局限性。你可以使用 std::list 吗?还有你到底想做什么。
  • 类播放列表是我必须放在二进制文件中的东西。我想给用户一个选项来插入一个播放列表(在他们的要求位置),创建一个播放列表(通过把它放入存在默认播放列表的文件,即为什么我使用条件 if(wmp[h].existp("Default playlist")),第三,用户应该能够删除播放列表并最终查看所有现有播放列表。
  • 终于完成了!输入,输出,删除都很好。只有一个小问题是“sr”正在获取内存值而不是序列号。文件中的值。因此,不是将第二个播放列表打印为 2.Second Playlist,而是打印 2609.Second Playlist。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
  • 2011-09-03
  • 2016-01-15
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多