[英]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();
}
一些評論:
假設文件只包含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.