分隔从文件中读取的行

Separating line read from a file c++

本文关键字:读取 文件 分隔      更新时间:2023-10-16

我在一个文件中有一个图书列表,它由id、书名、作者、出版年份、类型等组成。我找不到如何从文件Books.txt中读取

(提取)

1   The Da Vinci Code   Dan Brown   2003    mistery-detective   20  3
2   Think and Grow Rich Napoleon Hill   1937    non-fiction 50  5
3   Harry Potter and the Half-Blood Prince  J. K. Rowling   2005    fantasy 92  8
4   The Catcher in the Rye  J. D. Salinger  1951    novel   100 6

以正确的方式struct数组信息,如Book_list[0]。id应为1,Book_list[0].name =达芬奇密码,等等。其理念是,每条信息都用标签分隔开来。如果我问得不够清楚,我先道歉。

#include <iostream>
#include <string>
#include <fstream>
struct Book
{
    int id;
    std::string name;
    std::string author;
    int year;
    std::string genre;
    int times_given;
    int available;
};
int main()
{
    int book_list_size = 500;
    int number_of_books = 0;
    Book book_list[book_list_size];
    std::ifstream book_input_stream("Books.txt");
    std::string line;
    while (std::getline(book_input_stream, line))
    {
        ++number_of_books;
    }
    book_input_stream.close();
    book_input_stream.open("Books.txt");
    for (int i = 0; i < number_of_books; i++)
    {
        book_input_stream >> book_list[i].id >> book_list[i].name
                >> book_list[i].author >> book_list[i].year
                >> book_list[i].genre >> book_list[i].times_given
                >> book_list[i].available;
    }
    for (int i = 0; i < number_of_books; i++)
    {
        std::cout << book_list[i].id << " " << book_list[i].name << " "
                << book_list[i].author << " " << book_list[i].year << " "
                << book_list[i].genre << " " << book_list[i].times_given << " "
                << book_list[i].available << std::endl;
    }
    book_input_stream.close();
    return 0;
}

如果您有几行数据,其中的字段用制表符分隔,则正常的解决方案是逐行读取,然后中断将每一行转换成其各自的数据,然后最后进行转换任何需要转换的数据。Book应该有构造函数;尽管在c++ 11中,可以不使用,构造函数仍然使事情更简洁。例如:

std::vector<Book> books;
std::string line;
int lineNumber = 0;
while ( std::getline( input ) ) {
    ++ lineNumber;
    std::vector<std::string> fields( split( line, 't' ) );
    if ( fields.size() != 7 /* || other validations */ ) {
        //  error handling...
        //  it's nice when the error messages contain the line number
    } else {
        books.push_back(
            Book(
                asInt( fields[0] ),
                fields[1],
                fields[2],
                asInt( fields[3] ),
                fields[4],
                asInt( fields[5] ),
                asInt( fields[6] ) ) );
}
对于这个问题,您可以(通常应该)定义一个>>Book操作符
std::istream&
operator>>( std::istream& source, Book& dest )
{
    std::string line;
    std::getline( source, line );
    if ( source ) {
        std::vector<std::string> fields( split( line, 't' ) );
        if ( fields.size() != 7 /* || other validations */ ) {
            source.setstate( std::ios_base::failbit );
        } else {
            dest = Book(
                    asInt( fields[0] ),
                    fields[1],
                    fields[2],
                    asInt( fields[3] ),
                    fields[4],
                    asInt( fields[5] ),
                    asInt( fields[6] ) );
    }
    return source;
}

然后,你所需要做的就是:

std::vector<Book> books;
Book book;
while ( input >> book ) {
    books.push_back( book );
}

首先是这个叫做std::vector的奇妙类,它基本上是一个可变长度数组,所以您不必读取文件两次。你可以添加

#include <vector>

放到文件的顶部,并写入:

std::vector<Book> book_list;

创建列表。然后,您可以使用:

添加新书。
book_list.push_back(Book());

并以熟悉的方式访问已添加的图书:

book_list[0].id

对于从文件中读取,>>操作符一直读取到任何空格,仅在制表符处停止,使用

string s;
getline(book_input_stream, s, 't');

当然,像所有get*函数一样,空白将不会被跳过,所以请确保您只使用一个选项卡,或者使用book_input_stream >> std::ws来跳过额外的空白。

一种可能的读书方式是:

Book b;
book_input_stream >> b.id >> std::ws;
getline(book_input_stream, b.name, 't');
book_input_stream >> std::ws;
getline(book_input_stream, b.author, 't');
book_input_stream >> b.year >> std::ws;
getline(book_input_stream, b.genre, 't');
book_input_stream >> b.times_given >> b.available;
book_list.push_back(b);