首页 文章

从文件中读取不正确的数据(C,fstream)

提问于
浏览
0

整个问题:

问题3您是五金店的所有者,需要保留一份库存,告诉您有哪些不同的工具,每个工具有多少以及每个工具的成本 . 编写一个程序,将随机访问文件“hardware.dat”初始化为100个空记录,让您输入有关每个工具的数据,使您能够列出所有工具,让您删除不再拥有的工具的记录并允许您更新文件中的任何信息 . 工具识别号应为记录号 . 使用以下信息启动文件 .


My Code :

int question_3()
{
    cout << "Question 3" << endl;

    fstream hardware;
    hardware.open("hardware.dat" , ios::binary | ios::out);


//Create 100 blank objects---------------------------------------------------------------
    if (!hardware)
    {
        cerr << "File could not be opened." << endl;
        exit(1);
    }

    HardwareData myHardwareData;

    for (int counter = 1; counter <= 100; counter++)
    {
        hardware.write(reinterpret_cast< const char * >(&myHardwareData), sizeof(HardwareData));
    }

    cout << "Successfully create 100 blank objects and write them into the file." << endl;

    hardware.close();
    hardware.open("hardware.dat" , ios::binary | ios::out | ios::in);


//Write data-----------------------------------------------------------------------------
    int record;
    int quantity;
    float cost;
    string tool_name;

    cout << endl;
    cout << "Enter record number (1 to 100, 0 to end input) : ";
    cin >> record;

    while (record != 0)
    {
        cin.sync();
        cout << "Enter tool name : ";           getline(cin, tool_name);
        cout << "Enter quantity : ";            cin >> quantity;
        cout << "Enter cost : ";                cin >> cost;

        myHardwareData.setRecord(record);
        myHardwareData.setToolName(tool_name);
        myHardwareData.setQuantity(quantity);
        myHardwareData.setCost(cost);

        hardware.seekp((myHardwareData.getRecord() - 1) * sizeof(HardwareData));
        hardware.write(reinterpret_cast<const char *>(&myHardwareData), sizeof(HardwareData));

        cout << endl
            << "Enter record number (1 to 100, 0 to end input) : ";
        cin >> record;
    }

    cout << "Successfully write all input data into the file." << endl;


//Read data----------------------------------------------------------------------------
    cout << endl;
    outputDataLineHead();
    hardware.read(reinterpret_cast<char *>(&myHardwareData), sizeof(HardwareData));
    int counter = 0;
    cout << setprecision(2) << fixed;
    while (hardware && !hardware.eof())
    {
        if (myHardwareData.getRecord() != 0)
            outputDataLine(cout, myHardwareData);

        hardware.seekp(counter++ * sizeof(HardwareData));
        hardware.read(reinterpret_cast<char *>(&myHardwareData), sizeof(HardwareData));
    }

    return 0;
}


//Function for showing data in line form.-----------------------------------------------
void outputDataLineHead()
{
    cout << left << setw(17) << "Record No." 
         << left << setw(17) << "Tool Name"
         << left << setw(17) << "Quantity"
         << left << setw(17) << "Cost" << endl; 
}

void outputDataLine(ostream &output, const HardwareData &Object_in_file)
{
    output << left << setw(17) << Object_in_file.getRecord()
           << left << setw(17) << Object_in_file.getToolName()
           << left << setw(17) << Object_in_file.getQuantity()
           << left << setw(17) << Object_in_file.getCost() << endl;
}

HardwareData.h :

#ifndef HAREWAREDATA_H
#define HAREWAREDATA_H

#include <iostream>
using std::string;

class HardwareData
{
public :
    HardwareData(string name = "", int recd = 0, int qutity = 0, float cot = 0.0)
    {
        setToolName(name);
        setRecord(recd);
        setQuantity(qutity);
        setCost(cot);
    }

    void setToolName(string name)
    {
        const char *nameValue = name.data();
        int length = 0;
        length = (length < 15 ? length : 14);
        strncpy(tool_name, nameValue, length);
        tool_name[length] = '\n';
}

string getToolName() const
{
    return tool_name;
}

void setRecord(int recd)
{
    record = recd;
}

int getRecord() const
{
    return record;
}

void setQuantity(int qutity)
{
    quantity = qutity;
}

int getQuantity() const
{
    return quantity;
}

void setCost(float cot)
{
    cost = cot;
}

float getCost() const
{
    return cost;
}

private :
    char tool_name[15];
    int record;
    int quantity;
    float cost;
};

#endif

enter image description here

我想显示如下数据:

Record No.        Tool Name          Quantity         Cost
4                 electric hammer    3                34.32

怎么做到这一点?


Thank you for your attention.

2 回答

  • 1

    我认为您的问题是在读取数据时..请检查您的变量是否得到正确的数据..您可以通过计算字符或尝试打印它们来检查 .

    如果他们不正确 . 你可以使用我在下面使用的这样一个例子 .

    首先,我更喜欢你像这个例子一样阅读你的行;

    在这个例子中,我得到了面部的坐标 . 你应该改变参数..为了不读不需要数据

    std::string str;
        while(std::getline(in, str))
        {
            sscanf(str.c_str(), "%d %f %f", &fiducial.number, &fiducial.x, &fiducial.y);
    
            coord_Num[fiducial.number] = fiducial.get_number();
            coord_X[fiducial.number] = fiducial.get_x();
            coord_Y[fiducial.number] = fiducial.get_y();
    
        }
    

    如果一切都很好 . 你应该检查一下

    void outputDataLine(ostream &output, const HardwareData &Object_in_file)
    
  • 1

    这里的核心问题是,您正在读取/写入 HardwareData 类型的对象的字节,而不是您应该创建插入器/提取器,以便您可以实现正确的I / O语义 . 例如:

    //在HardwareData类中
    friend std :: ostream&operator <<(std :: ostream&,const HardwareData&);
    friend std :: istream&operator >>(std :: istream&,HardwareData&);

    这两个声明分别用于插入器和提取器 . 输入应包括提取到 recordtool_namequantitycost 数据成员;输出应该只是一个流插入,这是很容易实现的 .


    将格式化输入与未格式化输入混合时,通常存在问题,即残余换行禁止进一步输入 . 这似乎就是这样的情况:

    cin >> record;                                                             /*
    ^^^^^^^^^^^^^^                                                             */
    
    while (record != 0)
    {
        cin.sync();
        cout << "Enter tool name : ";           getline(cin, tool_name);
        //                                      ^^^^^^^^^^^^^^^^^^^^^^^^
    
        // ...
    }
    

    cin >> record; 完成后,流中会有一个换行符 . 该换行符将使 std::getline() 无法正常工作,因为 std::getline() 只读取到换行符 .

    这里的修复是通过使用 std::ws 操纵器忽略这个新行:

    std :: getline(std :: cin >> std :: ws,tool_name);
    // ^^^^^^^^^^^^^^^^^^^

    注意:我会更详细地讨论这个问题here .

    但是不需要这种手动提取,因为我们已经为我们的类定义了插入器和提取器 . 所以真正需要的是以下内容:

    while(std :: cin >> myHardwareData)
    {
    硬件<< myHardwareData;
    }

    要么

    std :: copy(std :: istream_iterator <HardwareData>(std :: cin),
    的std :: istream_iterator <HardwareData>(),
    的std :: ostream_iterator <HardwareData>(硬件));

    注意到我如何在 while 循环中检查 00 值 . 那是因为提取器通过将 record0 值反映为无效输入来处理它 . 如果发生这种情况,它会设置流的流状态,从而允许自己从_2606120中弹出:如果发生这种情况:

    std :: istream&operator >>(std :: istream&is,HardwareData&hd)
    {
    cout <<“输入记录号(1到100,0到结束输入):”;

    if((是>>记录)&&记录!= 0)
    {
    // ...
    其他
    {
    is.setstate(标准::的ios_base :: failbit);
    }
    // ...
    }


    并将其余代码更改为:

    std :: cout << myHardwareData;
    硬件>> myHardwareData;

    std :: cout << std :: setprecision(2)<< std :: fixed;
    而(硬件>> myHardwareData)
    {
    if(myHardwareData.getRecord()!= 0)
    std :: cout << myHardwareData;
    }

    我真的不知道 seekp 是什么用的 . 如果您详细说明,那将真正帮助我更准确地调整我的代码以满足您的需求 .

相关问题