如何将文件中的数据读取到 class 的数组中

How to read data from a file into an array of a class

此作业涉及编写一个程序,该程序将从文本文件中读取汽车代理商及其汽车(+汽车信息)。

具体来说,我应该读入汽车代理商名称、汽车代理商邮政编码,然后是汽车年份、制造商、型号、传感器及其可用性。

由于传感器在带有“{”和“}”的文本文件中的显示方式,我很难读取传感器。最大传感器也是 3 个,但每辆车并不总是 3 个。

我创建了 Sensor、Car 和 Agency 类。

输入文件(HighTechAgency.txt):

Enterprise 89502
2014 Toyota Tacoma 115.12 {gps} 1
2012 Honda CRV 85.10 {camera lidar} 0
2011 Toyota Rav4 65.02 {} 0
2009 Dodge Neon 45.25 {camera lidar radar} 1
2015 Ford Fusion 90.89 {lidar} 0

Sensor.h:

#ifndef SENSOR_H
#define SENSOR_H
#define MAX_CHAR 256

class Sensor{
    char type [MAX_CHAR];
    float extracost;
    static int gps_cnt, camera_cnt, lidar_cnt, radar_cnt;
public:
    Sensor();
    Sensor(char[]);
    Sensor(Sensor & other); 
    char* getType();
    float getExtraCost();
    void setType(char[]);
    void setExtraCost(char[]);
    void sensorCnt(char[]);
    static int getGPSCnt();
    static int getCameraCnt();
    static int getLidarCnt();
    static int getRadarCnt();
    static void resetGPSCnt();
    static void resetCameraCnt();
    static void resetLidarCnt();
    static void resetRadarCnt();
};

bool operator==(Sensor & sensor1, Sensor & sensor2);

#endif

Sensor.cpp:

#include "Sensor.h"
#include "myStrings.h"

int Sensor::gps_cnt = 0;
int Sensor::camera_cnt = 0;
int Sensor::lidar_cnt = 0;
int Sensor::radar_cnt = 0;

Sensor::Sensor(){
    type[0] = '[=13=]';
    extracost = 0;
}

Sensor::Sensor(char sensorName[]){
    setType(sensorName);
}

Sensor::Sensor(Sensor & other){ 
    setType(other.type);
}

char* Sensor::getType(){
    return type;
}

float Sensor::getExtraCost(){
    return extracost;
}

void Sensor::setType(char typeSensor[]){
    myStrings::strCpy(type,typeSensor);
    sensorCnt(typeSensor);
    setExtraCost(typeSensor);
}

void Sensor::setExtraCost(char newType[]){
    if(myStrings::strCmp(newType,"gps") == 0){
        extracost = 5;
    }
    if(myStrings::strCmp(newType, "camera") == 0){
        extracost = 10;
    }
    if(myStrings::strCmp(newType, "lidar") == 0){
        extracost = 15;
    }
    if(myStrings::strCmp(newType, "radar") == 0){
        extracost = 20;
    }
    if(myStrings::strCmp(newType, "") == 0){
        extracost = 0;
    }
}

void Sensor::sensorCnt(char sensorType[]){
    if(myStrings::strCmp(sensorType,"gps") == 0){
        gps_cnt++;
    }
    if(myStrings::strCmp(sensorType, "camera") == 0){
        camera_cnt++;
    }
    if(myStrings::strCmp(sensorType, "lidar") == 0){
        lidar_cnt++;
    }
    if(myStrings::strCmp(sensorType, "radar") == 0){
        radar_cnt++;
    }
}

int Sensor::getGPSCnt(){
return gps_cnt;
}

int Sensor::getCameraCnt(){
    return camera_cnt;
}

int Sensor::getLidarCnt(){
    return lidar_cnt;
}

int Sensor::getRadarCnt(){
    return radar_cnt;
}

void Sensor::resetGPSCnt(){
    gps_cnt = 0;
}

void Sensor::resetCameraCnt(){
    camera_cnt = 0;
}

void Sensor::resetLidarCnt(){
    lidar_cnt = 0;
}

void Sensor::resetRadarCnt(){
    radar_cnt = 0;
}

bool operator==(Sensor& sensor1, Sensor& sensor2){
    return (myStrings::strCmp(sensor1.getType(),sensor2.getType()) == 0);
}

Car.h:

#ifndef CAR_H
#define CAR_H
#define MAX_SENS 3

#include "Sensor.h"

class Car{
    char make[MAX_CHAR];
    char model[MAX_CHAR];
    int year;
    Sensor sensor[MAX_SENS];
    float baseprice, finalprice;
    bool available;
public:
    Car();
    Car(char[], char[], int, float, Sensor[], bool);
    Car(Car & other);
    char* getMake();
    char* getModel();
    int getYear();
    float getBasePrice();
    float getFinalPrice(); 
    bool getAvailable();
    void setMake(char[]);
    void setModel(char[]);
    void setYear(int);
    void setBasePrice(float);
    void setAvailable(bool);
    void updatePrice();
    void print();
    float estimateCost(int);
    void addSensor(Sensor[]);
};

#endif

Car.cpp:

#include <iostream>
#include "Car.h"
#include "myStrings.h"

Car::Car(){
    make[0] = '[=15=]';
    model[0] = '[=15=]';
    year = 0;
    baseprice = 0;
    finalprice = 0;
    available = false;
}

Car::Car(char newMake[], char newModel[], int newYear, float newBasePrice, Sensor newSensor[], bool newAvailable){
    setMake(newMake);
    setModel(newModel);
    setYear(newYear);
    setBasePrice(newBasePrice);
    setAvailable(newAvailable);
    addSensor(newSensor);
}

Car::Car(Car & other){
    setMake(other.make);
    setModel(other.model);
    setYear(other.year);
    setBasePrice(other.baseprice);
    setAvailable(other.available);
    addSensor(other.sensor);
}

char* Car::getMake(){
    return make;
}

char* Car::getModel(){
    return model;
}

int Car::getYear(){
    return year;
}

float Car::getBasePrice(){
    return baseprice;
}

float Car::getFinalPrice(){
    return finalprice;
}

bool Car::getAvailable(){
    return available;
}

void Car::setMake(char m_make[]){
    myStrings::strCpy(make,m_make);
}

void Car::setModel(char m_model[]){
    myStrings::strCpy(model,m_model);
}

void Car::setYear(int m_year){
    year = m_year;
}

void Car::setBasePrice(float m_baseprice){
    baseprice = m_baseprice;
}

void Car::setAvailable(bool m_available){
    available = m_available;
}

void Car::updatePrice(){
    for (int i = 0; i < MAX_SENS; i++){
        finalprice += sensor[i].getExtraCost();
    }
    finalprice += baseprice;
}

void Car::print(){
    updatePrice();
    std::cout << year << " " << make << " " << model << ", $" << baseprice << " per day,";
    for (int i = 0; i < MAX_SENS; i++){
        std::cout << " " << sensor[i].getType() << " ";
    }
    std::cout << " Available: " << std::boolalpha << available;
    std::cout << std::endl;
}

float Car::estimateCost(int days){
    return (finalprice * days); 
}

void Car::addSensor(Sensor sensorAdd[]){
    for (int i = 0; i < MAX_SENS; i++){
        char temp[MAX_CHAR];
        myStrings::strCpy(temp,sensorAdd[i].getType());
        sensor[i].setType(temp);
    }
}

Agency.h:

#ifndef AGENCY_H
#define AGENCY_H
#define MAX_CARS 5

#include "Car.h"

class Agency{
    char name[MAX_CHAR];
    int zipcode;
    Car inventory[MAX_CARS];
public:
    Agency();
    char* getName();
    int getZipcode();
    void setName(char[]);
    void setZipcode(int);
    void readAllData(Car []);
    void printAllData(Car []);
    void printAvailableCars(Car []); 
};

#endif

Agency.cpp:

#include <iostream>
#include <fstream>
#include "Agency.h"
#include "myStrings.h"
#define MAX_LEN 25

Agency::Agency(){
    name[0] = '[=17=]';
    zipcode = 0;
}

char* Agency::getName(){
    return name;
}

int Agency::getZipcode(){
    return zipcode;
}

void Agency::setName(char newName[]){
    myStrings::strCpy(name, newName);
}

void Agency::setZipcode(int newZipcode){
    zipcode = newZipcode;
}

void Agency::readAllData(Car data[]){
    char inputFile[MAX_LEN];
    int tempYear;
    char tempMake[MAX_CHAR];
    char tempModel[MAX_CHAR];
    float tempPrice;
    char tempSensor[MAX_CHAR];
    Sensor sens[MAX_SENS];
    bool tempAvailable;
    std::ifstream inputStream;

    std::cout << "Enter input file name: ";
    std::cin >> inputFile;

    inputStream.open(inputFile);

    if(inputStream.is_open()){

        std::cout << std::endl;
        std::cout << "*" << inputFile << " has been read.*" << std::endl;
        std::cout << std::endl;
        inputStream >> name >> zipcode;

        for(int i = 0; i < MAX_CARS; i++){
            inputStream >> tempYear >> tempMake >> tempModel >> tempPrice >> tempSensor >> tempAvailable;

            inventory[i].setYear(tempYear);
            inventory[i].setMake(tempMake);
            inventory[i].setModel(tempModel);
            inventory[i].setBasePrice(tempPrice);

            for (int j = 0; j < MAX_SENS; j++){
                sens[j].setType(tempSensor);
                myStrings::strCpy(tempSensor,sens[j].getType());
                inventory[i].addSensor(sens);
            }
        inventory[i].setAvailable(tempAvailable);
        }
    }

if(!inputStream.is_open()){
        std::cerr << "Failed to open file: " << inputFile << std::endl;
    }
}

void Agency::printAllData(Car data[]){
    std::cout << name << " " << zipcode;
    std::cout << std::endl;

    for(int i = 0; i < MAX_CARS; i++){
        inventory[i].print();
    }
    std::cout << std::endl;
}

void Agency::printAvailableCars(Car data[]){
    std::cout << name << " " << zipcode;
    for(int i = 0; i < MAX_CARS; i++){
        if(inventory[i].getAvailable() == 1){
        std::cout << inventory[i].getYear() << " " << inventory[i].getMake() << " " << inventory[i].getModel() << ", " << "$" << inventory[i].getFinalPrice() << " per day" << std::endl;
        }
    }
    std::cout << std:: endl;    
}

Proj4.cpp(驱动程序):(暂时测试读取输入)

#include <iostream>
#include <fstream>
#include "Agency.h"

int main()
{
    Agency data;
    Car cars[9];
    data.readAllData(cars);
    data.printAllData(cars);
    return 0;
}

这是打印到终端的内容。

Enterprise 89502
2014 Toyota Tacoma, 5.12 per day, {gps}  {gps}  {gps}  Available: true
2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false
2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false
2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false
2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false

但我想要的是:

Enterprise 89502
2014 Toyota Tacoma, 5.12 per day, {gps}  Available: true
2012 Honda CRV, .1 per day, {camera  lidar}  Available: false
2011 Toyota Rav4, .02 per day, {}  Available: false
2009 Dodge Neon, .25 per day, {camera  lidar  radar}  Available: true
2015 Ford Fusion, .89 per day, {lidar}  Available: true

我知道我在读取输入时存在问题。具体在 Agency.cpp.

中的函数 readAllData 中
void Agency::readAllData(Car data[]){
    char inputFile[MAX_LEN];
    int tempYear;
    char tempMake[MAX_CHAR];
    char tempModel[MAX_CHAR];
    float tempPrice;
    char tempSensor[MAX_CHAR];
    Sensor sens[MAX_SENS];
    bool tempAvailable;
    std::ifstream inputStream;

    std::cout << "Enter input file name: ";
    std::cin >> inputFile;

    inputStream.open(inputFile);

    if(inputStream.is_open()){

        std::cout << std::endl;
        std::cout << "*" << inputFile << " has been read.*" << std::endl;
        std::cout << std::endl;
        inputStream >> name >> zipcode;

        for(int i = 0; i < MAX_CARS; i++){
            inputStream >> tempYear >> tempMake >> tempModel >> tempPrice >> tempSensor >> tempAvailable;

            inventory[i].setYear(tempYear);
            inventory[i].setMake(tempMake);
            inventory[i].setModel(tempModel);
            inventory[i].setBasePrice(tempPrice);

            for (int j = 0; j < MAX_SENS; j++){
                sens[j].setType(tempSensor);
                myStrings::strCpy(tempSensor,sens[j].getType());
                inventory[i].addSensor(sens);
            }
        inventory[i].setAvailable(tempAvailable);
        }
    }

if(!inputStream.is_open()){
        std::cerr << "Failed to open file: " << inputFile << std::endl;
    }
}

我认为发生的事情是在读取价格后,它会查找下一组字符并将该字符 "word" 存储到 tempSensor 中。

第一行:

2014 Toyota Tacoma 115.12 {gps} 1

存储{gps}为tempSensor,存储3次

因此:

2014 Toyota Tacoma, 5.12 per day, {gps}  {gps}  {gps}  Available: true

第二行:

2012 Honda CRV 85.10 {camera lidar} 0 

它将{相机存储为tempSensor。并存储{相机三次。一旦遇到空白,它就会移动到 tempAvailable,但它会读取激光雷达,并且由于它需要一个 bool 输入,所以它会搞乱程序,这就是它继续为本田打印数据的原因。

因此:

2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false
2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false
2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false
2012 Honda CRV, .1 per day, {camera  {camera  {camera  Available: false

我知道我需要实现一些东西,以便它知道使用 tempSensor 查找 3 个词,并排除“{”和“}”。

虽然我不知道该怎么做。

如果必须使用字符数组,则使用 istream::getline 和分隔符:

static const unsigned int MAX_LENGTH_MAKE_MODEL = 256;
char make_and_model[MAX_LENGTH_MAKE_MODEL];
inputStream.getline(make_and_model, MAX_LENGTH_MAKE_MODEL, ','];

或者您可以阅读整行,然后搜索并提取子字符串:

static const unsigned int MAX_LINE_LENGTH = 4096;
char line_of_text[MAX_LINE_LENGTH];
inputStream.getline(line_of_text, MAX_LINE_LENGTH, '\n');
char * p_comma = strchr(line_of_text, ',');
//...

同时研究 strtok 函数。

您可以使用 std::istringstream 而不必使用您现在拥有的所有逻辑来解析字符串。您甚至可以保留所有字符数组而无需使用 std::string:

#include <sstream>
#include <iostream>

int main()
{
    char s[] = "2014 Toyota Tacoma 115.12 {gps} 1";
    int year;
    char make1[100], make2[100];
    double price;
    char category[100];
    int num;
    std::istringstream iss(s);
    iss >> year >> make1 >> make2 >> price >> category >> num;
    std::cout << year << "\n";
    std::cout << make1 << "\n";
    std::cout << make2 << "\n";
    std::cout << price << "\n";
    std::cout << category  << "\n";
    std::cout << num;    
}    

输出:

2014
Toyota
Tacoma
115.12
{gps}
1

如果大括号数据有多个元素,这里是解析数据的完整实现。它基本上在字符串中设置指针,然后将字符串的那部分提供给 std::istringstream 以使其进行解析:

#include <sstream>
#include <iostream>
#include <cstring>

int main()
{
    char s[] = "2014 Toyota Tacoma 115.12 {gps gps2 gps3} 1";

    // get the position of the braces and save this to a string
    char *pos1 = strchr(s,'{') + 1; // opening brace pointer
    char *pos2 = strchr(s,'}');     // closing brace pointer
    char curly_string[100] = {};
    strncpy(curly_string, pos1, pos2-pos1); // copy everything between these pointers

    // The last value is always located after the closing brace
    char *numpos = pos2 + 1;

    // parse the individual entries
    int year;
    char make1[100], make2[100];
    double price;
    int num;

    // Output the stuff before the curly brace
    std::istringstream iss(s);
    iss >> year >> make1 >> make2 >> price; 
    std::cout << year << "\n";
    std::cout << make1 << "\n";
    std::cout << make2 << "\n";
    std::cout << price << "\n";

    // Output the curly string stuff and its contents
    iss.clear();
    iss.str(curly_string);
    char one_category[100];
    while (iss >> one_category)
        std::cout << one_category << "\n";

    // output the last item (the number)
    iss.clear();
    iss.str(numpos);
    iss >> num;
    std::cout << num;
}    

输出:

2014
Toyota
Tacoma
115.12
gps
gps2
gps3
1

请注意,使用 std::string 作为类型而不是 char 数组更容易。使用 char 数组很浪费,因为我必须声明包含 100 个条目的数组。