답변:
먼저 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)
}
토큰 기반 파싱은 개행을 방해하지 않기 때문에 (1)과 (2)를 섞어서는 안됩니다. 따라서 getline()
토큰 기반 추출 후 이미 라인.
int a, b; char c; while ((infile >> a >> c >> b) && (c == ','))
while(getline(f, line)) { }
과 오류 처리에 대한 내용은 다음 기사를 참조하십시오 : gehrcke.de/2011/06/… (이 글을 게시하면 나쁜 양심이 필요하지 않다고 생각합니다. 이 답변 날짜).
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;
하지만 o
in ofstream
은 약자입니다 output
. 파일 (입력)을 읽으려면을 사용하십시오 ifstream
. 읽고 쓰려면 use를 사용하십시오 fstream
.
C ++에서 파일을 한 줄씩 읽는 것은 몇 가지 다른 방식으로 수행 될 수 있습니다.
가장 간단한 방법은 std :: ifstream을 열고 std :: getline () 호출을 사용하여 루프하는 것입니다. 코드는 깨끗하고 이해하기 쉽습니다.
#include <fstream>
std::ifstream file(FILENAME);
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
// using printf() in all tests for consistency
printf("%s", line.c_str());
}
file.close();
}
또 다른 가능성은 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 ++ 버전보다 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
std::cout
vs 의 기본 동작의 알려진 단점을 측정하고있을 수 있습니다 printf
.
printf()
일관성을 위해 모든 경우에 함수 를 사용하도록 코드를 편집했습니다 . 나는 또한 std::cout
모든 경우에 사용하려고 시도했지만 이것은 아무런 차이가 없었습니다. 방금 텍스트에서 설명했듯이 프로그램의 출력으로 이동 /dev/null
하여 라인을 인쇄하는 시간이 측정되지 않습니다.
cstdio
. 설정을 시도해보아야합니다 std::ios_base::sync_with_stdio(false)
. 훨씬 더 나은 성능을 얻었을 것입니다 ( 동기화가 꺼질 때 구현 정의 되었으므로 보장되지는 않습니다 ).
좌표가 쌍으로 묶여 있기 때문에 구조체를 작성하지 않겠습니까?
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
}
int
스트림에서 두 개의 토큰 을 읽을 수 없으면 어떻게됩니까 operator>>
? 역 추적 파서를 사용하여 어떻게 작동시킬 수 있습니까 (즉, operator>>
실패 할 때 스트림을 이전 위치로 롤백하면 false 또는 이와 유사한 것을 반환합니다)?
int
토큰 을 읽을 수 없으면 is
스트림이 평가 false
되고 해당 시점에서 읽기 루프가 종료됩니다. operator>>
개별 읽기의 리턴 값을 확인하여 이를 감지 할 수 있습니다 . 스트림을 롤백하려면을 호출 is.clear()
합니다.
operator>>
이 말을하는 것이 더 정확 is >> std::ws >> coordinates.x >> std::ws >> coordinates.y >> std::ws;
당신이 당신의 입력 스트림이 공백 스키핑 모드에 있음을 가정합니다 그렇지.
입력이 다음과 같은 경우 허용되는 답변을 확장합니다.
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();
파일을 수동으로 닫을 필요는 없지만 파일 변수의 범위가 더 큰 경우 종료하는 것이 좋습니다.
ifstream infile(szFilePath);
for (string line = ""; getline(infile, line); )
{
//do something with the line
}
if(infile.is_open())
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
}