Connecting Tech Pros Worldwide Forums | Help | Site Map

A better way to tail a file

Count Dracula
Guest
 
Posts: n/a
#1: Jul 19 '05
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";
}

Johan den Boer
Guest
 
Posts: n/a
#2: Jul 19 '05

re: A better way to tail a file


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" <lk3a@esinet.net> schreef in bericht
news:fcadc9c4.0308091318.3a6a5050@posting.google.c om...[color=blue]
> 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";
> }[/color]


Johan den Boer
Guest
 
Posts: n/a
#3: Jul 19 '05

re: A better way to tail a file


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" <lk3a@esinet.net> schreef in bericht
news:fcadc9c4.0308091318.3a6a5050@posting.google.c om...[color=blue]
> 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";
> }[/color]


Closed Thread