Skip to content

Instantly share code, notes, and snippets.

@kampersanda
Last active July 21, 2021 18:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kampersanda/fa2cf283b5fd2809f3def17579558aab to your computer and use it in GitHub Desktop.
Save kampersanda/fa2cf283b5fd2809f3def17579558aab to your computer and use it in GitHub Desktop.
後ろ向きにファイル読み込み
read_backward:read_backward.cpp
c++ -O3 -o read_backward read_backward.cpp -std=c++17 -Wall -Wextra -pedantic
clean:
rm -r -f read_backward
#include <stdint.h>
#include <stdio.h>
#include <chrono>
#include <fstream>
#include <iostream>
static char OUTPUT[1024 * 1024]; // up to 1 MiB
// std::ifstreamのバッファの中身を確認
void show_streambuf(std::ifstream& ifs) {
std::cout << "streambuf: ";
std::filebuf* buf = ifs.rdbuf();
const std::streamsize num = buf->in_avail();
for (std::streamsize i = 0; i < num; i++) {
std::cout << char(buf->sbumpc());
}
for (std::streamsize i = 0; i < num; i++) {
buf->sungetc();
}
std::cout << std::endl;
}
// std::ifstremによるシンプルな順方向読み込み
void read_forward(const char* filename) {
std::ifstream ifs(filename, std::ios::binary);
size_t i = 0;
for (char c; ifs.get(c);) {
OUTPUT[i++] = c;
}
ifs.close();
}
// std::ifstremによるシンプルな逆方向読み込み
void read_backward(const char* filename) {
std::ifstream ifs(filename, std::ios::binary);
ifs.seekg(-1, std::ios::end); // 読み込みポインタを最後の文字に設定
size_t i = 0;
for (char c; ifs.get(c);) { // 読み込みポインタ += 1
// show_streambuf(ifs);
OUTPUT[i++] = c;
ifs.seekg(-2, std::ios::cur); // 読み込みポインタ -= 2
}
ifs.close();
}
// FILEによるバッファを使った逆方向読み込み
void read_backward_buffering(const char* filename) {
// バッファ
constexpr std::streamsize bufsize = 1024;
char buffer[bufsize];
FILE* fp = fopen(filename, "rb");
fseek(fp, 0L, SEEK_END); // 読み込みポインタをファイル末尾に設定
const int64_t filesize = ftell(fp); // ファイルサイズ
size_t i = 0;
for (auto end = filesize; end > 0;) {
const auto beg = std::max<int64_t>(0, end - bufsize);
const auto readsize = end - beg;
fseek(fp, -readsize, SEEK_CUR); // 読み込みポインタを設定
fread(buffer, 1, readsize, fp); // バッファに読み込み
fseek(fp, -readsize, SEEK_CUR); // 読み込んだ分をリセット
for (auto j = readsize - 1; j >= 0; --j) {
OUTPUT[i++] = buffer[j];
}
end = beg;
}
fclose(fp);
}
int main(int argc, char** argv) {
if (argc != 2) {
std::cerr << "Argument error" << std::endl;
return 1;
}
const char* filename = argv[1];
{
const auto start_tp = std::chrono::high_resolution_clock::now();
read_forward(filename);
const auto stop_tp = std::chrono::high_resolution_clock::now();
const auto dur_ms = std::chrono::duration_cast<std::chrono::milliseconds>(stop_tp - start_tp);
std::cerr << "read_forward: " << dur_ms.count() << " ms" << std::endl;
}
{
const auto start_tp = std::chrono::high_resolution_clock::now();
read_backward(filename);
const auto stop_tp = std::chrono::high_resolution_clock::now();
const auto dur_ms = std::chrono::duration_cast<std::chrono::milliseconds>(stop_tp - start_tp);
std::cerr << "read_backward: " << dur_ms.count() << " ms" << std::endl;
}
{
const auto start_tp = std::chrono::high_resolution_clock::now();
read_backward_buffering(filename);
const auto stop_tp = std::chrono::high_resolution_clock::now();
const auto dur_ms = std::chrono::duration_cast<std::chrono::milliseconds>(stop_tp - start_tp);
std::cerr << "read_backward_buffering: " << dur_ms.count() << " ms" << std::endl;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment