Writing to the top of a text file preserving the rest of the doc.

Started by
12 comments, last by Antheus 14 years, 9 months ago
Hi guys, i have a load of HTML files that are lacking things like the <title> tags and stuff, and the files lose the changed stuff every time i re-publish, it's a problem with frontpage and templates. Anyway i thought hay, i can fix this, get a file read the first line for the file and the second line for the text that needs to go at the top of the file e.g. <title> title <title>. Now i planned it all out but i came to write a file with fstream (and it's associated classes). The only way i can open write and save (i have found) is with fstream::ate. I try to seek to the beggining of the doc, i've tried several times and realised that it only seeks within the current line. Also there is no function i have found that lets you seek lines. Apart from reading the whole file editing it in memory and re-writing the whole thing back to file (this seems a bit excessive), is there any way i can fill the empty line at the top of the file? I'm surprised i have encountered this problem, is there a libary that can be used, a portable lib would be best. JamesCobras
Advertisement
Quote:Original post by JamesCobras
Apart from reading the whole file editing it in memory and re-writing the whole thing back to file (this seems a bit excessive), is there any way i can fill the empty line at the top of the file?
Nope - that's the way it's always done. Files have no concept of lines, they're just a stream of bytes. Which is also why you can't seek to line X; only seek forwards X bytes.
Right well if it's just 1 long line, why can't i seek to the first charater in the whole file.

e.g.

1------------ (10bytes)
------------- (10bytes)
------------- (10bytes)
------------- (10bytes)
2------------


I'm on line 2 how do i seek to point 1? It doesn't seem to want to.
I uderstand that to a computer it looks like one long line, but how do i seek to the start of the long line? e.g. back 40 bytes, it just doesn't seem to work?! I'd of thought it would.

JamesCobras

[Edited by - JamesCobras on July 23, 2009 6:30:10 AM]
If you want to *overwrite* data at the start of a file, you can do that like this:

fstream file("filename.txt", ios::ate | ios::in | ios::out );file.seekp(0, ios::beg);file << "Overwriting the first characters in file.";


However, if your first line is nothing but a new line (which is most likely) then you have to realize that to you'll merely overwrite that newline and then start overwriting the second line's data. The new line character(s) is/are nothing more than additional characters to the file stream. It doesn't understand the difference between one line and the text.
Ah, lovely just what i was looking for.

But why wasn't the following code working like that:

#include <fstream>using namespace std;int main () {  fstream HTML;  HTML.open ("test.txt", fstream.out | fstream::ate);  // >> i/o operations here <<    HTML.seekg(0,ios_base::beg);  HTML.write("\nhello4\n",8);  HTML.close();  return 0;}
Err no it didn't work guys.

text file before:
asdfasdgasdfgsdfgasdg adsfg sadfg  fg   sdffg h hfgv asghfv asmnhdfv sadfg  asdfg as dg  sdf h a dfg  a  sdfgas  fg   adf   g    ad   g    adfg     ad     fhadfhasdfg      adfgh      adfh       asdf      g      adsfg       asdf      ga       sdfg a      fg       a        sd        fah         a         fg          a          fg           adfh


After:
hello


Code:
#include <fstream>using namespace std;int main () {  fstream HTML;  HTML.open ("test.txt", ios::out | ios::ate);  // >> i/o operations here <<    HTML.seekg(0,ios_base::beg);  HTML << "hello";  HTML.close();  return 0;}


Wanted:
After:
helloasdfasdfasgasdfgrgaserg


Hope that clears a load of stuff up and helps you help me.

JamesCobras

P.S. i think that the code i was using was synominous with the code you gave me (got same results)
Read the entire file into memory. Replace the lines. Write the entire file back out.

This is the easiest way.
#include <string>#include <vector>#include <fstream>#include <iterator>#include <algorithm>typedef std::vector<std::string> FileData;FileData read(const std::string &filename){    FileData result;    std::ifstream in(filename.c_str());    std::string line;    while(std::getline(in, line))    {        result.push_back(line);    }    return result;}void write(const std::string &filename, const FileData &data){   std::ofstream out(filename.c_str());   std::copy(data.begin(), data.end(), std::ostream_iterator<std::string>(out, "\n"));}void go(const std::string &filename){   FileData data = read(filename);   // modify data   write(filename, data);}

This gives you a nice line based view of the file in the vector.
Your code is overwriting the entire file because you forgot to include ios::in in your opening flags.

HTML.open("test.txt", ios::in | ios::out | ios::ate);


However, you still do not appear to be listening to the more important information that others are giving you in this thread.

In a file, a newline is represented not by a long empty line of spaces ready for you to overwrite, but by a single newline character (or possibly a newline and a carriage return sequence on some systems).

So the following:

this is sometext


looks like this in terms of characters in the file (\n is a newline character):

\nthis is some\ntext


If I now overwrite from pos 0 with the word "hello", it becomes:

hello is some\ntext


which in an editor is shown as:

hello is sometext


Quote:Original post by JamesCobras
Apart from reading the whole file editing it in memory and re-writing the whole thing back to file (this seems a bit excessive), is there any way i can fill the empty line at the top of the file?


There is no empty line at the top of the file. There is (maybe some spaces then) a newline character at the start of the file.

James - load the entire file into memory using an ios::in file stream, then close the stream, then reopen the file with an ios::out file stream, then write your custom header to this stream, then write the previously loaded input file to the stream (or even better use std::ifstream and std::ofstream then you can't accidentally muddle up your read/write operations on the wrong stream).

This is not excessive - this is how these things are done.

[EDIT] And while I was typing this, rip-off has provided the code to do just that.
Oh, kk, yeah thanks guys yep missing that iso::in was the killer.
Wow, i thought because I was only outputing that it wasn't needed.

Also i quite like the array idea to get things sorted and exact.

Thanks Guys, your help is appreciated.

James
Have your template in file: template.txt.
Let your real file be: real.html

sed '1r template.txt' < real.html > newReal.html


This will insert contents of template.txt after first line, producing newReal.html.

This topic is closed to new replies.

Advertisement