Page 1 of 1

[SOLVED] Inserting a new line in a file

Posted: Thu May 20, 2010 12:40 pm
by dandymcgee
I'm trying to insert a new line of text at the beginning of a large file. I have two questions.

1) Why is my current method writing rubbish at the end (see below)?
2) Will this work on very large (>1MB) text files? If not, could you recommend another solution?

test.txt

Code: Select all

Test text file
Test text file
Test text file
main.cpp

Code: Select all

#include <fstream>
#include <sstream>

int main( int argc, char *argv[] )
{
	//String stream
	std::stringstream newTextStream;
	newTextStream << "New line of text!";

	//Open file
	std::fstream file;
	file.open( "test.txt" );

	if( !file.is_open() ){
		return 1;
	}

	//Get length of file
	file.seekg ( 0, std::ios::end );
	int length = file.tellg();
	file.seekg ( 0, std::ios::beg );

	//Temporarily store file contents
	char *tempFile = new char[length];
	file.read( tempFile, length );
	file.close();

	//Rewrite file
	file.clear();
	file.open( "test.txt", std::ios::out );

	if( !file.is_open() ){
		return 1;
	}

	file << newTextStream.str() << std::endl << tempFile << std::endl;
	file.close();
}
Resulting test.txt:

Code: Select all

New line of text!
Test text file
Test text file
Test text fileÍÍÍÍýýýý««««««««îþîþîþ
As always, thanks for reading!

[Unrelated request]
Perhaps syntax highlighted code tags could be considered as a forum update?

Re: Inserting a new line in a file

Posted: Thu May 20, 2010 12:57 pm
by short
First of all, I created a 12.1mb file and ran your code on it. It worked perfectly. There were no problems. It just added a newline to the end of the textfile which is weird, a few minutes and I should figure that out.

Re: Inserting a new line in a file

Posted: Thu May 20, 2010 1:03 pm
by GroundUpEngine
I checked this out too, your code does exactly what it's supposed to, I debugged it in VC.
-Your output file seems to be corrupt or something, very strange

-With your test.txt the output was ->

Code: Select all

New line of text!
Test text file
Test text file
Test text file

-I also tryed this code on a huge 100MB file of junk and it just added an endline

Re: Inserting a new line in a file

Posted: Thu May 20, 2010 1:20 pm
by short

Code: Select all

	newTextStream << "New line of text!";

Code: Select all

file << newTextStream.str() << std::endl << tempFile << std::endl;
Try this:

Code: Select all

       newTextStream << "New line of text!\n";

Code: Select all

file << newTextStream.str()  << tempFile;
This will result in adding a line to the beginning of your file, without adding another line at the end of the file. Also it may remove the random characters being added to the end of your file. I can't reproduce the random characters being added to your text file, so try it and post back.

Re: Inserting a new line in a file

Posted: Thu May 20, 2010 2:12 pm
by xiphirx
do you have extra white space characters after those lines of text in test.txt?

Try cerr'ing the length that you get, and comparing it to manually getting the length. Your text editor is probably adding the rubbish.

Re: Inserting a new line in a file

Posted: Thu May 20, 2010 6:14 pm
by short
xiphirx wrote:do you have extra white space characters after those lines of text in test.txt?

Try cerr'ing the length that you get, and comparing it to manually getting the length. Your text editor is probably adding the rubbish.
I tried it, and the length was exactly as it should be. If its not it is definitely his text editor.

Re: Inserting a new line in a file

Posted: Thu May 20, 2010 8:41 pm
by dandymcgee
short wrote: Try this:

Code: Select all

       newTextStream << "New line of text!\n";

Code: Select all

file << newTextStream.str()  << tempFile;
This will result in adding a line to the beginning of your file, without adding another line at the end of the file. Also it may remove the random characters being added to the end of your file. I can't reproduce the random characters being added to your text file, so try it and post back.
Same output.
xiphirx wrote:do you have extra white space characters after those lines of text in test.txt?

Try cerr'ing the length that you get, and comparing it to manually getting the length. Your text editor is probably adding the rubbish.
There's no way it's my text editor, no functional text editor would add that much rubbish to a text file (even a MS product like Notepad which is what I'm using). If it was the text editor, wouldn't it make sense that I would see if it i closed the file and reopened it? I don't, not until I run the program on it.

And to your first question, there is no extra white space.

It has to be reading the junk memory past the end of the char* into the file, but I don't understand why.

Re: Inserting a new line in a file

Posted: Fri May 21, 2010 1:44 am
by Scoody
I'm guessing it's because you're just handing it the char* array which doesn't have the \0 terminator since you've only read the amount of chars in the file and reads past the array until a \0 is encountered.
read wrote:Notice that this is an unformatted input function and what is extracted is not stored as a c-string format, therefore no ending null-character is appended at the end of the character sequence.
Use file.write(tempFile,length) or make sure you add that \0 yourself.

Re: Inserting a new line in a file

Posted: Fri May 21, 2010 12:14 pm
by dandymcgee
Scoody wrote:I'm guessing it's because you're just handing it the char* array which doesn't have the \0 terminator since you've only read the amount of chars in the file and reads past the array until a \0 is encountered.
read wrote:Notice that this is an unformatted input function and what is extracted is not stored as a c-string format, therefore no ending null-character is appended at the end of the character sequence.
Use file.write(tempFile,length) or make sure you add that \0 yourself.
Thanks! This was part of the solution. I still had to account for length being reported longer than I expected.

Working solution:

Code: Select all

#include <fstream>
#include <sstream>
#include <iostream
int main( int argc, char *argv[] )
{
	//String stream
	std::stringstream newTextStream;
	newTextStream << "New line of text!\n";

	//Open file
	std::fstream file;
	file.open( "test.txt" );

	if( !file.is_open() ){
		return 1;
	}

	//Get length of file
	file.seekg ( 0, std::ios::end );
	int length = file.tellg();
	file.seekg ( 0, std::ios::beg );

	//Temporarily store file contents
	char *tempFile = new char[length];
	for( int i = 0; i < length; i++ ){
		tempFile[i] = '\0';
	}
	file.read( tempFile, length );
	file.close();

	//Rewrite file
	file.clear();
	file.open( "test.txt", std::ios::out );

	if( !file.is_open() ){
		return 1;
	}

	file << newTextStream.str();
	char *discard = strchr( tempFile, (int)'\0' );
	file.write( tempFile, discard-tempFile );
	file.close();
}
I have no idea why the original worked for other people.. but this should make it work universally. Thanks for your help all! ;)

Re: [SOLVED] Inserting a new line in a file

Posted: Sat May 22, 2010 1:50 am
by Scoody
It worked for others because they were lucky that the '\0' was the first char after the array.

Instead of doing this:

Code: Select all

   for( int i = 0; i < length; i++ ){
      tempFile[i] = '\0';
   }
Use memset to fill large memory chunks with the same value:

Code: Select all

memset(tempFile,0,length);
You could try opening the file as binary and use file.write, that way you don't have to mess around with filling the array and strchr. Use newTextStream.str().c_str() (IIRC :)) to get a char* for your string for file.write.

Re: [SOLVED] Inserting a new line in a file

Posted: Sat May 22, 2010 11:32 am
by dandymcgee
Scoody wrote: You could try opening the file as binary and use file.write, that way you don't have to mess around with filling the array and strchr. Use newTextStream.str().c_str() (IIRC :)) to get a char* for your string for file.write.
I'm not sure I understand. I'm using strchr to discard trailing null characters from the c-string.

Re: [SOLVED] Inserting a new line in a file

Posted: Sat May 22, 2010 1:21 pm
by M_D_K
C strings are null terminated by design (so you know where a string stops), when writing them anywhere (stdout, file, whatever) the null is not written; it's just used so you can figure out how long a string is.

Considering that strlen is basically this:

Code: Select all

int strlen(const char *str)
{
    int i;
    for(i = 0; *(str+i) != 0; i++)
        ;
    return i;
}
that garbage you get is probably cause of a lack of \0 at the end of a string (it can't tell where it ends).

Re: [SOLVED] Inserting a new line in a file

Posted: Sat May 22, 2010 2:14 pm
by dandymcgee
M_D_K wrote: that garbage you get is probably cause of a lack of \0 at the end of a string (it can't tell where it ends).
You still don't understand. I'm not getting any garbage anymore.

I'm filling char *tempFile with 0's;
Getting the file length (which is always larger than the actual amount of text);
Reading the file into tempFile (which leaves the extra space at the end of tempFile filled with the 0's I initially wrote);
Discarding the extra 0's;
Writing the contents of tempFile to the new file.

The only problem that remains is the fact that length is always incorrect in the positive. Since this causes no loss in functionality at all, I've elected to simply discard extra characters. If you see a better solution to this minor issue, feel free to enlighten me. ;)