your programing

C ++에서 ifstream을 사용하여 한 줄씩 파일 읽기

lovepro 2020. 10. 3. 11:22
반응형

C ++에서 ifstream을 사용하여 한 줄씩 파일 읽기


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");

먼저 다음을 만듭니다 ifstream.

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

두 가지 표준 방법은 다음과 같습니다.

  1. 모든 줄이 두 개의 숫자로 구성되어 있고 토큰별로 읽는다고 가정합니다.

    int a, b;
    while (infile >> a >> b)
    {
        // process pair (a,b)
    }
    
  2. 라인 기반 구문 분석, 문자열 스트림 사용 :

    #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)
    }
    

토큰 기반 구문 분석이 줄 바꿈을 먹지 않기 때문에 (1)과 (2)를 혼합해서는 안됩니다. 따라서 getline()토큰 기반 추출 후 사용하면 가짜 빈 줄이 생길 수 있습니다 . 이미 라인.


ifstream파일에서 데이터를 읽는 데 사용 :

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

정말로 한 줄씩 읽어야한다면 다음과 같이하십시오.

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

그러나 아마도 좌표 쌍을 추출해야 할 수도 있습니다.

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

최신 정보:

코드에서 사용 ofstream myfile;하지만 oin ofstreamoutput. 파일 (입력)에서 읽으려면 ifstream. 읽고 쓰려면을 사용하십시오 fstream.


C ++에서 한 줄씩 파일을 읽는 것은 몇 가지 다른 방법으로 수행 될 수 있습니다.

[빠른] std :: getline () 루프

가장 간단한 방법은 std :: ifstream을 열고 std :: getline () 호출을 사용하여 루프하는 것입니다. 코드는 깨끗하고 이해하기 쉽습니다.

#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();
}

[빠른] 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);

벤치 마크-어느 것이 더 빠릅니까?

위의 코드로 몇 가지 성능 벤치 마크를 수행했으며 그 결과는 흥미 롭습니다. 100,000 줄, 1,000,000 줄 및 10,000,000 줄의 텍스트가 포함 된 ASCII 파일로 코드를 테스트했습니다. 각 텍스트 줄에는 평균 10 개의 단어가 포함됩니다. 프로그램은 -O3최적화 로 컴파일되고 /dev/null측정에서 로깅 시간 변수를 제거하기 위해 출력이로 전달됩니다 . 마지막으로, 각 코드 조각은 printf()일관성 을 위해 함수 와 함께 각 줄을 기록합니다 .

결과는 각 코드가 파일을 읽는 데 걸린 시간 (ms)을 보여줍니다.

두 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

여기에 이미지 설명 입력


좌표가 쌍으로 함께 속해 있기 때문에 구조를 작성하지 않으시겠습니까?

struct CoordinatePair
{
    int x;
    int y;
};

그런 다음 istream에 대해 오버로드 된 추출 연산자를 작성할 수 있습니다.

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
}

입력이 다음과 같은 경우 수락 된 답변을 확장합니다.

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();

이 답변은 Visual Studio 2017 및 컴파일 된 콘솔 응용 프로그램과 관련된 위치를 텍스트 파일에서 읽으려는 경우입니다.

먼저 텍스트 파일 (이 경우 test.txt)을 솔루션 폴더에 넣습니다. 컴파일 후 applicationName.exe와 같은 폴더에 텍스트 파일 유지

C : \ Users \ "사용자 이름"\ source \ repos \ "solutionName"\ "solutionName"

#include <iostream>
#include <fstream>

using namespace std;
int main()
{
    ifstream inFile;
    // open the file stream
    inFile.open(".\\test.txt");
    // check if opening a file failed
    if (inFile.fail()) {
        cerr << "Error opeing a file" << endl;
        inFile.close();
        exit(1);
    }
    string line;
    while (getline(inFile, line))
    {
        cout << line << endl;
    }
    // close the file stream
    inFile.close();
}

이것은 C ++ 프로그램에 데이터를로드하는 일반적인 솔루션이며 readline 함수를 사용합니다. CSV 파일의 경우 수정할 수 있지만 구분 기호는 여기에 공백입니다.

int n = 5, p = 2;

int X[n][p];

ifstream myfile;

myfile.open("data.txt");

string line;
string temp = "";
int a = 0; // row index 

while (getline(myfile, line)) { //while there is a line
     int b = 0; // column index
     for (int i = 0; i < line.size(); i++) { // for each character in rowstring
          if (!isblank(line[i])) { // if it is not blank, do this
              string d(1, line[i]); // convert character to string
              temp.append(d); // append the two strings
        } else {
              X[a][b] = stod(temp);  // convert string to double
              temp = ""; // reset the capture
              b++; // increment b cause we have a new number
        }
    }

  X[a][b] = stod(temp);
  temp = "";
  a++; // onto next row
}

파일을 수동으로 닫을 필요는 없지만 파일 변수의 범위가 더 큰 경우 그렇게하는 것이 좋습니다.

    ifstream infile(szFilePath);

    for (string line = ""; getline(infile, line); )
    {
        //do something with the line
    }

    if(infile.is_open())
        infile.close();

참고 URL : https://stackoverflow.com/questions/7868936/read-file-line-by-line-using-ifstream-in-c

반응형