Web Hosting Talk







View Full Version : C++: Need function to return last line in a file


marshallm
09-30-2004, 12:48 PM
I'm really hoping someone can help me out with this one. I've NEVER been able to get my arms around string handling in C for some reason. I understand that strings are basically arrays of char with a '\0' at the end, but beyond that, I have no clue what I'm doing wrong.

Now, I'm using MS Visual C++, and what I need to do is this...

I need a C++ function that will read a file, and return the last line as a string. I basically want to say this (I'll use PHP to illustrate)


$string = getLastLine($filename);

function getLastLine($filename)
{
// open the file

// find the last line including '\n', and call it $lastLine


return($lastLine);
}


Can anyone clue me in on how to do this in C++? I'd greatly appreciate it. Also if anyone can point me to some resources that may help explain string handling in C/C++ that would be awesome too. It probably needs to be written like it's targeted at a 5 year old in order for me to pick it up! ;)

Thanks much,

Mark

sea otter
09-30-2004, 04:54 PM
Here you go :)

Comments follow in the next post.


#include <iostream>
#include <fstream>
#include <string>

using namespace std;

bool getLastLine(const char *filename, string &lastLine)
{

#define _LL_BUFFSIZE_ 2048

lastLine.clear(); // regardless, zero out our return string
if (!filename || !*filename) // if no file to work on, return false
return false;

char buff[_LL_BUFFSIZE_]; // our temporary input buffer

ifstream is;
is.open(filename);

if (!is) // return false if couldn't open file
return false;

is.seekg (0, ios::end); // go to end of file
int length = is.tellg(); // find out how large it is
is.seekg(length-min(length,_LL_BUFFSIZE_),ios::beg); // seek back from end a short ways

// read in each line of the file until we're done
buff[0]=0;
do {
// uncomment if you want to skip empty lines or lines that start with whitespace
// fancier logic is probably called for
/*
if (!isspace(buff[0]) && buff[0] != 0)
lastLine = buff;
*/
} while (is.getline(buff, _LL_BUFFSIZE_));

is.close();

return true;
}

int main (int argc, char * const argv[]) {

string lastLine;

if (!getLastLine("FILE_NAME_HERE",lastLine))
cout << "Error opening file!" << endl;
else
cout << lastLine << endl;

return 0;
}

sea otter
09-30-2004, 04:59 PM
okayyyyyyy,

"old fashioned" string handling in C is quite different than string handling in C++ using the Standard C++ Library (the former STL), and both are totally different than string handling in Java, PHP, C#, VB, etc......

I've posted the code in C++ format, because it seemed more like what you wanted. I don't know where to send you for online reference material since I don't use any for C++ (been doing this too long!).

I've commented the code to a degree, but please don't hesitate to post back with questions if you have any.

Note that you will need to change FILE_NAME_HERE in the main() routine to something meaningful :)

Code is tested, checked against missing files, large files, small files.

Hope it helps.

marshallm
09-30-2004, 11:29 PM
You are a coding machine!! :D

Thank you so sooo much! I'm pretty good at the logic part of things, but as you probably know, when it comes time to make something work in a language that you don't use everyday, sometimes I need to see a working example to figure out what's going on.

I've tested this, and it does indeed work, so thank you very much. I do have one question...

what does this do:


using namespace std;


??

I'm going to continue on with my project here, and hopefully I'll be able to do the rest of it just by looking at the example you made for me.

Thanks again!

Mark


edit: actually I have two questions...
Does working with strings this way mean that I can't access them as char arrays, and do things like strlen() on them?

sea otter
10-01-2004, 12:18 AM
No Prob; mini-projects keep me sharp :)

To answer the two questions:

1. using namespace std

Namespaces in C++ are a way of grouping variables/functions/classes/etc. to help reduce name conflicts which arise when you include things with the same name from different sources.

All classes in the Standard C++ Library are created in the "std" namespace, basically declared as such:

namespace std {
class string {
.....
};
}

By adding using namespace std; to my code, I tell the compiler to look for class definitions in the "std" namespace as well as in the immediate non-namespaced scope of the source file and its non-namespaced includes.

If I didn't have the using namespace line, all of the classes I used in the sample code would have required the prepended scope operator std:: (std::ifstream, std::string, etc).

2. using string like a char[]

You can use a string like a regular const char * (i.e., in "read only mode") by calling its c_str() method. This does NOT work if you want to modify the contents of the string in C functions. So you could pass myString.c_str() to strlen, but not as the destination in strcpy().

You'll notice in the code I posted that I actually use a regular char array in the do/while loop for precisely this reason.

nnormal
10-01-2004, 10:11 AM
my simpletons version :::

using namespace std;

is the same thing as

#include <stdlib.h>

in most cases.

but listen to sea otter. He's got it right. This is MUCH easier to do with the fstream lib than the stdio lib. stdio is a major pain in the tuchas.

marshallm
10-01-2004, 10:23 AM
Thanks folks.

My concern is that I need to go through these strings one character at a time once I retrieve them and do some "math" type stuff with them. All this and speed will be of paramount importance.

Sea Otter's code will most certainly get me started, and I am quite thankful, but I may need to adapt as I get further into the project.

We'll see.

Thanks again!

Mark

sea otter
10-01-2004, 10:35 AM
Originally posted by marshallm
Thanks folks.

My concern is that I need to go through these strings one character at a time once I retrieve them and do some "math" type stuff with them. All this and speed will be of paramount importance.

Sea Otter's code will most certainly get me started, and I am quite thankful, but I may need to adapt as I get further into the project.

We'll see.

Thanks again!

Mark

just so you know, to do that, you could use (as previously mentioned)


string lastLine;

const char *pbuff = lastLine.c_str();

// now you can use pbuff like a read-only character array

int length = strlen(pbuff);

// etc.


As always, post back if you have questions.


@nnormal, I'm an old "C" hand as well (at least I'm assuming you are) :) I think I've used C++ streams maybe twice in my life, and one of those was here. You just get used to doing things a certain way, I guess. But as you said, this is certainly "cleaner" than the old way, and it's also more au courrant. Wouldn't wan't new coders learning to write "old skool", would we? :D

pjmmartins
11-03-2010, 08:02 AM
Sea Otter, your code works perfectly. I've tried to compile it with g++ and returns me the last value of my data file. However, I still have a problem. When I compile it with bcc32, it returns me 0, as the last line. I don't know why bcc32 doesn't work like g++.
Besides that, I have to open the data file from another computer, using remote desktop, so I need to use fopen function. The name of the other computer is andromeda. If I substitute FILE_NAME_HERE by \\andromeda\data.txt in your code, it won't work. Can you help me?

Best Regards,

Paulo

Maxnet
11-03-2010, 10:06 AM
Sea Otter, your code works perfectly.

You are replying to an old post of an user that hasn't logged in since 2006.



Besides that, I have to open the data file from another computer, using remote desktop, so I need to use fopen function. The name of the other computer is andromeda. If I substitute FILE_NAME_HERE by \\andromeda\data.txt in your code, it won't work. Can you help me?


Try substituting FILE_NAME with \\\\andromeda\\data.txt first.

If that doesn't work, you probably need some Windows specific API call to open the file.
I think istream already uses fopen() internally.

pjmmartins
11-03-2010, 10:47 AM
Thank you very much, Maxnet. It worked, I can finally open the file in other computer :) but bcc32 still can't compile the file correctly like g++ does. It compiles my c++ file, but when I run it it should give the last value of the data file. It gives 0 instead. I post the code adapted to read the last value of my file:

#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <string>
#include <stdio.h>

using namespace std;

bool getLastLine(const char *filename, string &lastLine)
{

#define _LL_BUFFSIZE_ 2048

lastLine.clear(); // regardless, zero out our return string
if (!filename || !*filename) // if no file to work on, return false
return false;

char buff[_LL_BUFFSIZE_]; // our temporary input buffer

ifstream is;
is.open(filename);

if (!is) // return false if couldn't open file
return false;

is.seekg (0, ios::end); // go to end of file
int length = is.tellg(); // find out how large it is
is.seekg(length-min(length,_LL_BUFFSIZE_),ios::beg); // seek back from end a short ways

// read in each line of the file until we're done
buff[0]=0;
do {
// uncomment if you want to skip empty lines or lines that start with whitespace
// fancier logic is probably called for

if (!isspace(buff[0]) && buff[0] != 0)
lastLine = buff;

} while (is.getline(buff, _LL_BUFFSIZE_));

is.close();

return true;
}

//int main (int argc, char * const argv[]) {
int main () {


string lastLine;


if (!getLastLine("\\\\andromeda\\data\\data.txt",lastLine))
cout << "Error opening file!" << endl;
else

string lastLine;

const char *pbuff = lastLine.c_str();

// now you can use pbuff like a read-only character array

int i = atoi(pbuff);


printf ("The value read is %d. The double is %d.\n",i,i*2);



return 0;

}

Best Regards,

Paulo

Maxnet
11-03-2010, 04:12 PM
if (!getLastLine("\\\\andromeda\\data\\data.txt",lastLine))
cout << "Error opening file!" << endl;
else
string lastLine;


What are you trying to achieve with the "else string lastLine;"?

pjmmartins
11-04-2010, 06:43 AM
That was part from older code. That's doing nothing. I already removed it. Actually, my only problem now is that this code works perfectly with g++ and visual studio 2008, but doesn't work with bcc. I need to compile and run it with bcc.

Best Regards,

Paulo Martins