簡體   English   中英

從文件中讀取不正確的數據(C ++,fstream)

[英]Improper Data Reading from File (C++, fstream)

整個問題:

問題3

您是五金店的所有者,需要保留一份庫存,告訴您您擁有的不同工具,每個工具的數量以及每個工具的成本。 編寫一個程序,將隨機訪問文件“hardware.dat”初始化為100個空記錄,讓您輸入有關每個工具的數據,使您能夠列出所有工具,讓您刪除不再擁有的工具的記錄並允許您更新文件中的任何信息。 工具識別號應為記錄號。 使用以下信息啟動文件。

在此輸入圖像描述


我的代碼:

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

在此輸入圖像描述

我想顯示如下數據:

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

怎么做到這一點?


感謝您的關注。

我認為您的問題是在讀取數據時..請檢查您的變量是否獲得正確的數據..您可以通過計算字符或嘗試打印它們來檢查。

如果他們不正確。 你可以使用我在下面使用的這樣一個例子。

首先,我更喜歡你像這個例子一樣閱讀你的行;

在這個例子中,我得到了面部的坐標。 你應該改變參數..為了不讀不需要數據

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)

這里的核心問題是,您正在向/從類型為HardwareData對象讀取和寫入字節,而您應該創建插入器/提取器,以便您可以實現正確的I / O語義。 例如:

 // Inside HardwareData class friend std::ostream& operator<<(std::ostream&, const HardwareData&); friend std::istream& operator>>(std::istream&, HardwareData&); 

這兩個聲明分別用於插入器和提取器。 輸入應包括提取到record ,工具tool_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); // ^^^^^^^^^^^^^^^^^^^ 

注意:我在這里更詳細地討論這個問題

但是不需要這種手動提取,因為我們已經為我們的類定義了插入器和提取器。 所以真正需要的是以下內容:

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

要么

 std::copy(std::istream_iterator<HardwareData>(std::cin), std::istream_iterator<HardwareData>(), std::ostream_iterator<HardwareData>(hardware)); 

注意到我如何在while循環中檢查了0值的record 那是因為提取器通過將record0值反映為無效輸入來處理它。 它設置了流的流狀態,如果發生這種情況,因此允許我們從被噴射while如果出現這種情況:

 std::istream& operator>>(std::istream& is, HardwareData& hd) { cout << "Enter record number (1 to 100, 0 to end input) : "; if ((is >> record) && record != 0) { // ... } else { is.setstate(std::ios_base::failbit); } // ... } 

並將其余代碼更改為:

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

我真的不知道搜索seekp的用途。 如果您詳細說明,那將真正幫助我更准確地調整我的代碼以滿足您的需求。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM