为什么我的程序无法从C ++中的二进制文件读取数据?

时间:2018-11-17 18:29:02

标签: c++

项目详细信息::我一直在尝试做一个名为“费用管理系统”的项目。

常规代码信息::我有一个“费用”类,它只有两个函数集并获取数据。我有一个main()函数,并且在其中我有menu()函数。

功能菜单::有4种情况,但只有两种是核心功能,情况1 ::将数据写入文件(费用明细),情况2读取并显示数据。

要解决的问题::我下面的情况2,功能代码不起作用,即不显示文件内容

以下代码是根据下面的答案:::

中所建议的建议进行修复的
    #include<iostream>
    #include<string.h>
    #include<fstream>

    using namespace std;



    class expense{
    public:
        //string
        char  date[20];
       // string 
        char title[20];
        double exp;

    public:

        void set_data(){
            cout<<"\nDate should be in the format\n i.e. day/moth/year eg 12/5/2018\n";
            cout<<"Enter the whole date\n";
            cin>>date;
            cout<<"Give title for expense\n";
            cin>>title;
            cout<<"Enter the total expense\n";
            cin>>exp;
        }

        void get_data(){
            cout<<"\tDate :: ";
            cout<<date;
            cout<<"\tTitle :: ";
            cout<<title;
            cout<<"\tExpense :: ";
            cout<<exp;
        }

    };

//header files 
    void menu();

//global variable's    
    int count=0;
    double tot=0;


//main function 
    int main()
    {
        menu(); //calling function 
        return 0;
    }

//function definition

    void menu(){
        int ch;
        int n;
        int i;
        char choice;
        string dd;
        int flag=0;
        expense exe;
        fstream fp;//file obj
        fp.open("test.dat",ios::app | ios::out | ios::in | ios::binary);
//opening file in different modes 
        if (!fp.good())
            cout << "file error\n";
    //loop below
        do {

            cout << "\n --------------------------------------- \n";
            cout << "Welcome to the Expense Management System" << endl;
            cout << "1.Enter the expense.\n";
            cout << "2.Display all the expenses.\n";
            cout << "3.Find expense for a particular date.\n";
            cout << "4.Display the total expenditure.\n";
            cout << "\nEnter the choice :: \n";
            cin >> ch;
            switch (ch) {
// case 1:: write data into the file 
                case 1:
                    exe.set_data();
                    fp.write(reinterpret_cast<char *>(&exe), sizeof(expense));
                    break;
                case 2:
//case 2 read all the data from the file 
                    fp.seekg(0,ios::beg);
                    cout << "All the expenses are listed below ::\n";
                    fp.read(reinterpret_cast<char *>(&exe), sizeof(expense));
                    exe.get_data();
                    while (fp.read(reinterpret_cast<char *>(&exe), sizeof(expense)))
                    {

                        cout<<"\n";
                        exe.get_data();

                    }
                    break;

                case 3:
//case 3 find the expense data from the file of the particular date
                fp.seekg(0,ios::beg);
                cout<<"Enter the date:\n";
                cin>>dd;
                while (fp.read(reinterpret_cast<char *>(&exe), sizeof(expense)))
                    {
                        if(fp.gcount() != sizeof(exe))
                        {
                        cout << "read error, we didn't get the right number of bytes\n";
                        break;
                        }

                        if((strcmp(exe.date,dd)==0)
                        {
                        flag=1;
                        exe.get_data(); 
                        }
                        cout<<"\n";
                    }
                    if(flag==0){
                    cout<<"Kindly Enter The Correct Date\n";
                    }
                    //fp.close();
                    break;
                case 4:
 //case 4:: calculates the total expense amount
                    fp.seekg(0,ios::beg);            
                    while (fp.read(reinterpret_cast<char *>(&exe), sizeof(expense)))
                    {
                        if(fp.gcount() != sizeof(exe))
                        {
                        cout << "read error, we didn't get the right number of bytes\n";
                        break;
                        }
                        tot+=exe.exp;

                    }
                    cout << "The Total Expenditure is ::\n"<<tot<<endl;
                    //fp.close();
                    break;


            }
            cout<<"\nDo you want to access the Main Menu?(y/n)\n";
            cin>>choice;
        }while(choice =='Y' || choice =='y');
   }

解决方案:::

  My problem is finally solved.I have drawn a conclusion since the program is working fine.

    Things to be fixed in the above program ::-

    1)While working with file.write()  and file.read() function  we should not include string variable so i changed every string variable into character array(IE each variable of fixed then no need to allocate memory additionally )

    Reason ::std::string does not fulfill the TriviallyCopyable requirement because, in order to hold strings of arbitrary length, it is allocating additional memory dynamically. This memory will not be part of the string's object representation and thus also not part of the object representation you acquire with the reinterpret_cast(thanks to eukaryota )

    2) I should reset the pointer to the start of the file every time before reading data from the file.( thanks to kerrytazi )
    E.G::
    fp.write(...);
    fp.seekp(0, std::ios::beg); /* set file pointer at the start of file */
    fp.read(...);

    3)Yes i have use the " reinterpret_cast<char *> " and it works cause i have used "char array" data type.

    4)Instead of writing a binary file we can also serialize a object in C++ and write data into text file also.
link :: https://thispointer.com/c-how-to-read-or-write-objects-in-file-serializing-deserializing-objects/


5)TO read multiple  data from a file using while loop will not work if we use while( !file.eof()) which is explained by the link below.
link :: https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong

2 个答案:

答案 0 :(得分:3)

fp.write(reinterpret_cast<char *>(&exe), sizeof(expense));
fp.read(reinterpret_cast<char *>(&exe), sizeof(expense))

这些绝对不会做您想在这里做的事情。在少数情况下,这种方法是可行的,即使这样,以这种方式写入的文件也无法移植。

reinterpret_cast<char*>(&exe)获得的指针将指向对象exe的地址,从那里进行读取将为您提供对象exe对象表示 ,基本上是存储在内存中该位置的实际字节,不一定足够的信息来重建对象的完整状态。

将字节序列写入文件并通过第二行代码从文件中读取来重新加载字节序列,仅在exe具有 TriviallyCopyable 的情况下足以重建exe类型。非正式地,除了其他方面之外,该概念还要求重构对象状态所需的所有数据都位于对象的存储器本身中,而不是位于通过例如图1所示的链接而来的另一个存储器位置中。指针成员。在您的情况下,std::string不满足 TriviallyCopyable 的要求,因为为了容纳任意长度的字符串,它正在动态分配额外的内存。该内存将不属于string的对象表示形式,因此也不属于您通过reinterpret_cast获取的对象表示形式。

如果您不确定100%地做什么,则应该永远不要使用reinterpret_cast

您需要正确地序列化expense结构,并以您选择的格式将其写入文件。如果您想正确执行的话,这是一项艰巨的任务。如果您想粗略地做,假设字符串中没有空格,那么:

fp << exe.date << exe.title << exe.exp << "\n";

可能是一种方法。

答案 1 :(得分:0)

写入文件后,您需要将文件指针移回。

fp.write(...);
fp.seekp(0, std::ios::beg); /* set file pointer at the start of file */
fp.read(...);

工作原理:

/* file:       */
/*       ^     */

fp.write("test", 4);

/* file: test  */
/*       ----^ */

fp.seekp(0, std::ios::beg);

/* file: test  */
/*       ^     */

fp.read(outBuffer, 4);

/* file: test  */
/*       ----^ */
相关问题