A better way to tail a file

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";
}
 
J

Johan den Boer

Hi,

Look for the last modification date/time for the file. Install a timer to
read this date/time every xxx seconds or minutes
I f the modification has been changed read the file until the end is reached
i.e.

......
read file until end
fill variable lastmodified with last time file modified;
......
while(true)
{
signal SIGALRM, timerEvent );
alarm( 5 ) // every 5 seconds
}
.......

void timerEvent()
{
struct stat st;

// fd file descriptor open file
fstat( fd, &st );
if( st.st_mtime != lastmodified )
{
read file until end of file
}
lastmodified = st.st_mtime;
}


Count Dracula said:
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";
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,260
Messages
2,571,038
Members
48,768
Latest member
first4landlord

Latest Threads

Top