首页 文章

使用C中的ifstream逐行读取文件

提问于
浏览
496

file.txt的内容是:

5 3
6 4
7 1
10 5
11 6
12 3
12 4

其中 5 3 是坐标对 . 如何在C中逐行处理此数据?

我能够得到第一行,但是如何获得文件的下一行?

ifstream myfile;
myfile.open ("text.txt");

7 回答

  • -3

    使用命令行参数:

    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <algorithm>
    #include "print.h"
    
    using namespace std;
    
    int main (int argc, char *argv[]) 
    {
        vector<string> list;
        ifstream in_stream;
        string line;
        in_stream.open(argv[1]);
    
        while(!in_stream.eof())
        {
            in_stream >> line;
            list.push_back(line);
        }
        in_stream.close();
        print(list);
        sort(list.begin(), list.end());
        print(list);
    }
    
  • 0

    使用 ifstream 从文件中读取数据:

    std::ifstream input( "filename.ext" );
    

    如果你真的需要逐行阅读,那么这样做:

    for( std::string line; getline( input, line ); )
    {
        ...for each line in input...
    }
    

    但您可能只需要提取坐标对:

    int x, y;
    input >> x >> y;
    

    Update:

    在您的代码中使用 ofstream myfile; ,但 ofstream 中的 o 代表 output . 如果要从文件中读取(输入),请使用 ifstream . 如果要同时读写,请使用 fstream .

  • 5

    首先,制作一个 ifstream

    #include <fstream>
    std::ifstream infile("thefile.txt");
    

    两种标准方法是:

    • 假设每行包含两个数字并按令牌读取令牌:
    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
    • 基于行的解析,使用字符串流:
    #include <sstream>
    #include <string>
    
    std::string line;
    while (std::getline(infile, line))
    {
        std::istringstream iss(line);
        int a, b;
        if (!(iss >> a >> b)) { break; } // error
    
        // process pair (a,b)
    }
    

    如果你在基于令牌的提取之后使用 getline() 已经到达一行的末尾,那么你不应该吞噬新行,所以你最终会得到虚假的空行 .

  • 738

    在C中逐行读取文件可以通过某些不同的方式完成 .

    [Fast]循环使用std :: getline()

    最简单的方法是使用std :: getline()调用打开std :: ifstream和循环 . 代码干净且易于理解 .

    #include <fstream>
    
    std::ifstream file(FILENAME);
    if (file.is_open()) {
        std::string line;
        while (getline(file, line)) {
            // using printf() in all tests for consistency
            printf("%s", line.c_str());
        }
        file.close();
    }
    

    [Fast]使用Boost的file_description_source

    另一种可能性是使用Boost库,但代码更加冗长 . 性能与上面的代码非常相似(使用std :: getline()循环) .

    #include <boost/iostreams/device/file_descriptor.hpp>
    #include <boost/iostreams/stream.hpp>
    #include <fcntl.h>
    
    namespace io = boost::iostreams;
    
    void readLineByLineBoost() {
        int fdr = open(FILENAME, O_RDONLY);
        if (fdr >= 0) {
            io::file_descriptor_source fdDevice(fdr, io::file_descriptor_flags::close_handle);
            io::stream <io::file_descriptor_source> in(fdDevice);
            if (fdDevice.is_open()) {
                std::string line;
                while (std::getline(in, line)) {
                    // using printf() in all tests for consistency
                    printf("%s", line.c_str());
                }
                fdDevice.close();
            }
        }
    }
    

    [最快]使用C代码

    如果性能对您的软件至关重要,您可以考虑使用C语言 . 此代码可以比上面的C版本快4-5倍,请参阅下面的基准测试

    FILE* fp = fopen(FILENAME, "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);
    
    char* line = NULL;
    size_t len = 0;
    while ((getline(&line, &len, fp)) != -1) {
        // using printf() in all tests for consistency
        printf("%s", line);
    }
    fclose(fp);
    if (line)
        free(line);
    

    基准 - 哪一个更快?

    我已经使用上面的代码完成了一些性能基准测试,结果很有趣 . 我用ASCII文件测试了代码,其中包含100,000行,1,000,000行和10,000,000行文本 . 每行文本平均包含10个单词 . 程序使用 -O3 优化进行编译,并将其输出转发到 /dev/null ,以便从测量中删除记录时间变量 . 最后但并非最不重要的是,每段代码都使用 printf() 函数记录每一行以保持一致性 .

    结果显示每段代码读取文件所用的时间(以毫秒为单位) .

    两种C方法之间的性能差异很小,在实践中不应有任何区别 . C代码的性能使得基准测试令人印象深刻,并且在速度方面可以改变游戏规则 .

    10K lines     100K lines     1000K lines
    Loop with std::getline()         105ms          894ms          9773ms
    Boost code                       106ms          968ms          9561ms
    C code                            23ms          243ms          2397ms
    
  • 9

    既然你的坐标是成对的,为什么不为它们写一个结构呢?

    struct CoordinatePair
    {
        int x;
        int y;
    };
    

    然后你可以为istreams编写一个重载的提取运算符:

    std::istream& operator>>(std::istream& is, CoordinatePair& coordinates)
    {
        is >> coordinates.x >> coordinates.y;
    
        return is;
    }
    

    然后你可以直接将坐标文件读入这样的矢量:

    #include <fstream>
    #include <iterator>
    #include <vector>
    
    int main()
    {
        char filename[] = "coordinates.txt";
        std::vector<CoordinatePair> v;
        std::ifstream ifs(filename);
        if (ifs) {
            std::copy(std::istream_iterator<CoordinatePair>(ifs), 
                    std::istream_iterator<CoordinatePair>(),
                    std::back_inserter(v));
        }
        else {
            std::cerr << "Couldn't open " << filename << " for reading\n";
        }
        // Now you can work with the contents of v
    }
    
  • 13

    虽然不需要手动关闭文件,但如果文件变量的范围更大,最好这样做:

    ifstream infile(szFilePath);
    
        for (string line = ""; getline(infile, line); )
        {
            //do something with the line
        }
    
        if(infile.is_open())
            infile.close();
    
  • 147

    扩展已接受的答案,如果输入是:

    1,NYC
    2,ABQ
    ...
    

    您仍然可以应用相同的逻辑,如下所示:

    #include <fstream>
    
    std::ifstream infile("thefile.txt");
    if (infile.is_open()) {
        int number;
        std::string str;
        char c;
        while (infile >> number >> c >> str && c == ',')
            std::cout << number << " " << str << "\n";
    }
    infile.close();
    

相关问题