回答:
最初に、ifstream
:
#include <fstream>
std::ifstream infile("thefile.txt");
2つの標準的な方法は次のとおりです。
すべての行が2つの数値で構成されていて、トークンごとにトークンを読み取ると仮定します。
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
。読み取りと書き込みの両方を行う場合は、を使用してくださいfstream
。
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
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
ストリームから2つのトークンを読み取ることができない場合は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 \ "username" \ 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
}