入力ファイルの後ろからk行表示する関数

printtail.png

最も単純な方法

  • 1回ファイルを全部読んで、全部で何行あるのか調べる
  • そのあと、またファイルポインタを最初に戻す。
  • 最初から呼んでって「後ろからk行の場所」になったら出力しはじめる
#include <stdio.h>
#include <conio.h>
#include <string>
#include <fstream>
#include <iostream>
using namespace std;
//後ろからk行表示関数
bool printTail(string filename,int k){
    ifstream ifs;
    ifs.open(filename,ios::in);
    char line[256];
    int linecount=0;
    while(!ifs.eof()){
        ifs.getline(line,sizeof(line));
        linecount++;
    }
    if(k>linecount){return false;}
    //本番の読み込み
    ifs.seekg(0,ios::beg);//最初に戻す
    int beginline=linecount-k;
    int l=0;
    while(!ifs.eof()){
        ifs.getline(line,sizeof(line));
        if(l>=beginline){
            cout<<line<<endl;
        }
        l++;
    }
    return true;
}
void main(){
    printTail("mytest.txt",3);
    printf("終了するには何か押してください");
    _getch();
}

ただしこの方法は、ファイルを2回読まなきゃいけないなど、ちょっとコストのかかる方法です。もっと賢い方法はないのかな?

もっと賢い方法

先述の方法より、メモリ量的には優しくない方法だけど、こっちの方が速度が速い。
更に、コードの量も少ない

bool printTail(string filename,const int k){
    ifstream ifs;
    ifs.open(filename,ios::in);
    string *line=new string[k];
    for(int i=0;i<k;i++){
        line[i]=new char[256];
    }
    int size=0;
    while(ifs.good()){
        getline(ifs,line[size%k]);
        size++;
    }
    int start=size>k ? (size%k):0;
    int count=min(k,size);
    //このままだと変な順番で並んでいるので
    //読み込んだ順に結果の出力
    for(int i=0;i<count;i++){
        cout<<line[(start+i)%k]<<endl;
    }
    return true;
}

competition fileread

サポートサイト Wikidot.com competitionfileread