C
Count Dracula
Is there a way to write a c++ program that will
print out the last few lines of a file without reading
the whole file? The implementations of 'tail' I have
seen all appear to be system dependent. I am looking for
a standard (portable) c++ solution that will do just a
fraction of tail's functionality. To make a long story short,
I am looking for suggestions that may help me improve the
speed of the following implementation for long input files:
/*
Command line utility to display the last few lines of a text file.
Usage: (1) tail <filename>
(2) tail <filename> <number of lines>
<filename> is the name of the file whose last few lines you want to
display
<number of lines> is the number of lines you want to display
(default is NumberOfLines)
Implementation note: this is an inefficient implementation that
reads the whole file
only to display a few lines from the end of the file.
*/
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <deque>
// Forward declarations
bool writetail(const std::string & filename, long numlines);
void usage(long NumberOfLines);
int main (int argc, char** argv)
{
const long NumberOfLines = 10;
long numlines;
std::string filename;
switch (argc)
{
case 2:
filename = argv[1];
numlines = NumberOfLines;
break;
case 3:
filename = argv[1];
numlines = strtol(argv[2], NULL, 10);
if (numlines <= 0 || errno == ERANGE)
{
std::cerr << argv[0] << ": error in second command line
argument" << '\n';
usage(NumberOfLines);
return 1;
}
break;
default:
std::cerr << argv[0] << ": missing command line arguments" <<
'\n';
usage(NumberOfLines);
return 1;
}
bool status = writetail(filename, numlines);
if (!status)
{
std::cerr << argv[0] << ": execution errors" << '\n';
usage(NumberOfLines);
return 1;
}
return 0;
}
bool writetail(const std::string & filename, long numlines)
{
std::ifstream input(filename.c_str());
if (!input)
{
std::cerr << "writehead: error opening file: " << filename <<
'\n';
return false;
}
std::string s;
std::deque<std::string> lines;
long kount = 0;
while (std::getline(input, s))
{
lines.push_back(s);
++kount;
if (kount == numlines) break;
}
while (std::getline(input, s))
{
lines.pop_front();
lines.push_back(s);
}
std::deque<std::string>::iterator p;
for (p = lines.begin(); p < lines.end(); ++p)
std::cout << *p << '\n';
input.close();
return true;
}
void usage(long NumberOfLines)
{
std::cerr << "usage: tail <filename> <number of lines (optional)>\n"
<<
" <filename> is the name of the file whose last
few lines you want to display\n" <<
" <number of lines> is the number of lines you
want to display (default is " <<
NumberOfLines << ")\n";
}
print out the last few lines of a file without reading
the whole file? The implementations of 'tail' I have
seen all appear to be system dependent. I am looking for
a standard (portable) c++ solution that will do just a
fraction of tail's functionality. To make a long story short,
I am looking for suggestions that may help me improve the
speed of the following implementation for long input files:
/*
Command line utility to display the last few lines of a text file.
Usage: (1) tail <filename>
(2) tail <filename> <number of lines>
<filename> is the name of the file whose last few lines you want to
display
<number of lines> is the number of lines you want to display
(default is NumberOfLines)
Implementation note: this is an inefficient implementation that
reads the whole file
only to display a few lines from the end of the file.
*/
#include <string>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <deque>
// Forward declarations
bool writetail(const std::string & filename, long numlines);
void usage(long NumberOfLines);
int main (int argc, char** argv)
{
const long NumberOfLines = 10;
long numlines;
std::string filename;
switch (argc)
{
case 2:
filename = argv[1];
numlines = NumberOfLines;
break;
case 3:
filename = argv[1];
numlines = strtol(argv[2], NULL, 10);
if (numlines <= 0 || errno == ERANGE)
{
std::cerr << argv[0] << ": error in second command line
argument" << '\n';
usage(NumberOfLines);
return 1;
}
break;
default:
std::cerr << argv[0] << ": missing command line arguments" <<
'\n';
usage(NumberOfLines);
return 1;
}
bool status = writetail(filename, numlines);
if (!status)
{
std::cerr << argv[0] << ": execution errors" << '\n';
usage(NumberOfLines);
return 1;
}
return 0;
}
bool writetail(const std::string & filename, long numlines)
{
std::ifstream input(filename.c_str());
if (!input)
{
std::cerr << "writehead: error opening file: " << filename <<
'\n';
return false;
}
std::string s;
std::deque<std::string> lines;
long kount = 0;
while (std::getline(input, s))
{
lines.push_back(s);
++kount;
if (kount == numlines) break;
}
while (std::getline(input, s))
{
lines.pop_front();
lines.push_back(s);
}
std::deque<std::string>::iterator p;
for (p = lines.begin(); p < lines.end(); ++p)
std::cout << *p << '\n';
input.close();
return true;
}
void usage(long NumberOfLines)
{
std::cerr << "usage: tail <filename> <number of lines (optional)>\n"
<<
" <filename> is the name of the file whose last
few lines you want to display\n" <<
" <number of lines> is the number of lines you
want to display (default is " <<
NumberOfLines << ")\n";
}