簡體   English   中英

將.txt文件讀入結構數組

[英]Reading .txt file into array of struct

我是編程初學者,我正在嘗試將 my.txt 文件讀入該程序中的結構數組,然后顯示數據然后對其進行排序,但程序只讀取第一行並且循環不會t 停止直到數組大小。 文件數據如下所示:

ID NAME ADDRESS AGE

編碼:

#include <iostream>
#include <fstream>
#include <string>
#include <conio.h>
using namespace std;

struct bio
{
    char name[50], address[50];
    int id, age; 
};

int main() 
{   
    int i = 0, arraysize = 1000;
    bio b[arraysize];
    fstream data;
    data.open("biodata.txt");
    while(data.read((char*)&b, sizeof(b[i])))
    {
        for (i = 1; i < 1000; i++)
        {
            data >> b[i].id >> b[i].name >> b[i].address >> b[i].age;
        }
    }
    for (i = 0; i < 1000; i++)
    {
        cout << b[i].id << " " << b[i].name << " " << b[i].address << " " << b[i].age << " " << endl;
    }
    data.close();
    getch();
}
#include <iostream>
#include <fstream>
#include <string>

#define ARRAY_SIZE 1000
#define FILE_NAME "biodata.txt"

using namespace std;

struct Bio
{
    int     m_id;
    string  m_name;
    string  m_address;
    int     m_age; 
};

int main() 
{ 
    Bio bio[ARRAY_SIZE];
    ifstream data;
    data.open(FILE_NAME);

    if (!data)
    {
        cout << "not file " << FILE_NAME;
        return 0;
    }

    for (int i = 0; i < ARRAY_SIZE && data.good(); ++i)
    {
        data >> bio[i].m_id >> bio[i].m_name >> bio[i].m_address >> bio[i].m_age;
    }

    for (int i = 0; i < ARRAY_SIZE ; ++i)
    {
        cout << bio[i].m_id << " " << bio[i].m_name << " " << bio[i].m_address << " " << bio[i].m_age << " " << endl;
    }

    data.close();
}

一些評論:

  1. 什么conio lib?
  2. struct (bio) 以大寫字母開頭
  3. 不要在 c++ 的 char 數組中使用,你有這個字符串。
  4. 將變量分隔為單獨的行(bot“char name[50],address[50];”)
  5. 最好將成員重命名為 m_X
  6. 關於你的“數組大小”。 如果它是您決定的 const 數字,請使用#define 來執行。 如果您需要整個文件,則根本不需要它。 (文件名也是)
  7. ifstream 而不是 fstream 數據。 你只需要閱讀。 你不想因為一些錯誤而改變你的數據。
  8. 檢查它的文件打開得很好
  9. 在您的代碼中,您檢查循環之前的 while。
  10. 在您的條件循環中檢查 data.good()。 它檢查它不是 eof 並且他的文件是可讀的。
  11. 讀取命令用於二進制文件
  12. 最好將加載文件和打印數據分離到 2 個不同的函數中。 我不是為了保存在你的模板上

假設文件只包含bio數組的數據(即頂部沒有標題),你在這里做了太多的讀取:

 while(data.read((char*)&b, sizeof(b[i]))) { for (i = 1; i < 1000; i++) { data >> b[i].id >> b[i].name >> b[i].address >> b[i].age; } }

data.read()將讀取結構,因此不需要data >> b[i].id等。

只需將循環更改為:

while (data.read((char*)&b[i], sizeof(bio)))
{
    i++;
}

將數據逐個元素讀入數組中。

但是,如果每個生物數據都在單獨的行上並且空格分隔每個字段,請參閱@gil 給出的另一個答案。

以下對於初學者來說可能有點復雜,但既然我們談論的是 C++,我們也應該尋找一種“更”面向目標的方法。

您設計了一個名為 bio 的 class。 在面向 object 的語言中,您將把 object 的所有數據以及在 class 中對該數據進行操作的所有函數放入。 所以你需要添加成員函數。 這個想法是將所有數據封裝在 object 中。 外界應該對class的細節一無所知。 您只需通過成員函數訪問它。 如果您想稍后進行更改,您將在類的成員函數中執行此操作。 並且程序的rest將繼續工作。

此外,我們絕對應該使用 C++ 語言功能。 例如,您應該將std::string用於字符串,而不是普通的舊 C 樣式字符 arrays。 您基本上不應該在 C++ 中使用 C-Style arrays。 相反,請使用 STL 容器。

那么,接下來讓我們設計一個帶有數據成員和成員函數的 class。 由於目前我們只需要輸入和 output 功能,因此我們覆蓋了插入器和提取器運算符。 這些操作員了解 class 的數據和行為,並會小心處理。

請參閱以下程序:

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>

struct Bio
{
    // Data
    unsigned int id{}; 
    std::string name{};
    std::string address{};
    unsigned int age{};

    // Overload extractor operator to read all data
    friend std::istream& operator >> (std::istream& is, Bio& b) {
        std::string textLine{};
        if (std::getline(is, textLine)) {
            std::istringstream textLineStream{textLine};
            textLineStream >> b.id >> b.name >> b.address >> b.age;
        }
        return is;
    }

    // Overload inserter operator to print the data 
    friend std::ostream& operator << (std::ostream& os, const Bio& b) {
        return os << b.id << " " << b.name << " " << b.address << " " << b.age;
    }
};

std::istringstream sourceFile{R"(1 John Address1 31
2 Paul Address2 32
3 Ringo Address3 33
4 George Address4 34
)"};

int main()
{
    // Define Variable and read complete source file
    std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};

    // Sort the guys by name
    std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});

    // Show output on screen
    std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));

    return 0;
}

一些評論。 在 StackOverflow 上,我無法使用文件。 所以在我的示例程序中,我使用了std::istringstream 但這也是一個std::istream 您也可以使用任何其他std::istream 所以如果你定義一個```std::ifstream to read from a file, then it will work in the same way as the

請看。 提取器操作符完成讀取源文件的全部工作。 它是封裝的。 沒有外面的 function 需要知道,它是怎么做的。

在主 function 中,我們定義了一個std::vector並使用它的范圍構造函數來指定數據的來源。 我們給它std::istream_iterator ,它遍歷輸入數據並調用提取器運算符,直到讀取所有內容。

然后我們按名稱排序並將結果復制到output。

您可能會注意到輸入數據中的字段以空格分隔。 這通常不適用於非原子數據。 名稱可以由兩部分組成,地址可以包含街道和城市。 為此,發明了 CSV(逗號分隔值)文件。

請在下面查看更現實的靈魂。

#include <iostream>
#include <iterator>
#include <vector>
#include <algorithm>
#include <sstream>
#include <regex>

struct Bio
{
    // Data
    unsigned int id{}; 
    std::string name{};
    std::string address{};
    unsigned int age{};

    // Overload extractor operator to read all data
    friend std::istream& operator >> (std::istream& is, Bio& b) {
        std::string line{}; 
        std::regex re{";"};
        if (std::getline(is, line)) {
            std::vector<std::string> token{std::sregex_token_iterator(line.begin(), line.end(), re, -1), std::sregex_token_iterator()};
            if (4 == token.size()) {
                b.id = std::stoul(token[0]); 
                b.name = token[1]; 
                b.address = token[2];
                b.age = std::stoul(token[3]); 
            }
        }
        return is;
    }

    // Overload inserter operator to print the data 
    friend std::ostream& operator << (std::ostream& os, const Bio& b) {
        return os << b.id << ", " << b.name << ", " << b.address << ", " << b.age;
    }
};


std::istringstream sourceFile{R"(1; John Lenon; Street1 City1; 31
2; Paul McCartney; Street2 City2; 32
3; Ringo Starr; Street3 City3; 33
4; George Harrison; Address4; 34
)"};

int main()
{
    // Define Variable and read complete source file
    std::vector<Bio> bio{std::istream_iterator<Bio>(sourceFile), std::istream_iterator<Bio>()};

    // Sort the guys by name
    std::sort(bio.begin(), bio.end(), [](const Bio& b1, const Bio& b2){ return b1.name < b2.name;});

    // Show output on screen
    std::copy(bio.begin(),bio.end(),std::ostream_iterator<Bio>(std::cout, "\n"));

    return 0;
}

我們有一個新的源格式,主要是不變的。 只是提取器運算符被修改。 在這里,我們使用不同的迭代器來獲取源數據。

暫無
暫無

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

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