file.txt の内容は次のとおりです。
5 3
6 4
7 1
10 5
11 6
12 3
12 4
は座標5 3
ペアです。このデータを C++ で 1 行ずつ処理するにはどうすればよいですか?
最初の行は取得できましたが、ファイルの次の行を取得するにはどうすればよいですか?
ifstream myfile;
myfile.open ("file.txt");
C++ でファイルを 1 行ずつ読み取るには、いくつかの方法があります。
最も簡単な方法は、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();
}
もう 1 つの可能性は 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()
最後になりましたが、一貫性を保つために、コードの各部分が関数を使用して各行をログに記録します。
結果は、コードの各部分がファイルを読み取るのにかかった時間 (ミリ秒) を示しています。
2 つの 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
}