ここでの多くは、あなた/あなたのアプリケーションにとってパフォーマンスが実際にどれほど重要かによって異なります。これは、扱うファイルの大きさに依存する傾向があります。数十キロバイトまたは数百キロバイトのようなものを扱う場合は、通常、機能する最も単純なコードを書くだけでよく、あまり心配する必要はありません。つまり、できることはすべて基本的に瞬時に実行されるため、コードを最適化してもあまり効果がありません。
一方、大量のデータ (数十メガバイト以上) を処理している場合、効率の差はかなり大きくなります。それをバイパスするためにかなり具体的な手順を踏まない限り(を使用するなどread
)、すべての読み取りがバッファリングされます-しかし、それはすべてが同じ速度になるという意味ではありません(または必ずしも同じ速度に非常に近い).
たとえば、基本的にあなたが尋ねたことを実行するためのいくつかの異なる方法の簡単なテストを試してみましょう:
#include <stdio.h>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <fstream>
#include <time.h>
#include <string>
#include <algorithm>
unsigned count1(FILE *infile, char c) {
int ch;
unsigned count = 0;
while (EOF != (ch=getc(infile)))
if (ch == c)
++count;
return count;
}
unsigned int count2(FILE *infile, char c) {
static char buffer[4096];
int size;
unsigned int count = 0;
while (0 < (size = fread(buffer, 1, sizeof(buffer), infile)))
for (int i=0; i<size; i++)
if (buffer[i] == c)
++count;
return count;
}
unsigned count3(std::istream &infile, char c) {
return std::count(std::istreambuf_iterator<char>(infile),
std::istreambuf_iterator<char>(), c);
}
unsigned count4(std::istream &infile, char c) {
return std::count(std::istream_iterator<char>(infile),
std::istream_iterator<char>(), c);
}
template <class F, class T>
void timer(F f, T &t, std::string const &title) {
unsigned count;
clock_t start = clock();
count = f(t, 'N');
clock_t stop = clock();
std::cout << std::left << std::setw(30) << title << "\tCount: " << count;
std::cout << "\tTime: " << double(stop-start)/CLOCKS_PER_SEC << "\n";
}
int main() {
char const *name = "test input.txt";
FILE *infile=fopen(name, "r");
timer(count1, infile, "ignore");
rewind(infile);
timer(count1, infile, "using getc");
rewind(infile);
timer(count2, infile, "using fread");
fclose(infile);
std::ifstream in2(name);
in2.sync_with_stdio(false);
timer(count3, in2, "ignore");
in2.clear();
in2.seekg(0);
timer(count3, in2, "using streambuf iterators");
in2.clear();
in2.seekg(0);
timer(count4, in2, "using stream iterators");
return 0;
}
入力として約 44 メガバイトのファイルを使用してこれを実行しました。VC++2012 でコンパイルすると、次の結果が得られました。
ignore Count: 400000 Time: 2.08
using getc Count: 400000 Time: 2.034
using fread Count: 400000 Time: 0.257
ignore Count: 400000 Time: 0.607
using streambuf iterators Count: 400000 Time: 0.608
using stream iterators Count: 400000 Time: 5.136
同じ入力を使用しますが、g++ 4.7.1 でコンパイルします。
ignore Count: 400000 Time: 0.359
using getc Count: 400000 Time: 0.339
using fread Count: 400000 Time: 0.243
ignore Count: 400000 Time: 0.697
using streambuf iterators Count: 400000 Time: 0.694
using stream iterators Count: 400000 Time: 1.612
そのため、すべての読み取りがバッファリングされているにもかかわらず、g++ では約 8:1、VC++ では約 20:1 の変動が見られます。もちろん、入力を読み取るすべての可能な方法をテストしたわけではありません。より多くの読書テクニックをテストした場合、より広い時間範囲が見られるとは思えませんが、それについては間違っている可能性があります. 実行するかどうかにかかわらず、少なくとも大量のデータを処理している場合は、処理速度を向上させるために 1 つの手法を別の手法よりも選択することを正当化できる十分なバリエーションが見られます。