0

I have a small program, that is meant to copy a small phrase from a file, but it appears that I am either misinformed as to how seekg() works, or there is a problem in my code preventing the function from working as expected.

The text file contains:

//Intro

previouslyNoted=false

The code is meant to copy the word "false" into a string

std::fstream stats("text.txt", std::ios::out | std::ios::in);
//String that will hold the contents of the file
std::string statsStr = "";
//Integer to hold the index of the phrase we want to extract
int index = 0;

//COPY CONTENTS OF FILE TO STRING
while (!stats.eof())
{
    static std::string tempString;
    stats >> tempString;
    statsStr += tempString + " ";
}

//FIND AND COPY PHRASE
index = statsStr.find("previouslyNoted=");     //index is equal to 8
//Place the get pointer where "false" is expected to be
stats.seekg(index + strlen("previouslyNoted="));     //get pointer is placed at 24th index
//Copy phrase
stats >> previouslyNotedStr;

//Output phrase
std::cout << previouslyNotedStr << std::endl;

But for whatever reason, the program outputs:

=false

What I expected to happen:

I believe that I placed the get pointer at the 24th index of the file, which is where the phrase "false" begins. Then the program would've inputted from that index onward until a space character would have been met, or the end of the file would have been met.

What actually happened:

For whatever reason, the get pointer started an index before expected. And I'm not sure as to why. An explanation as to what is going wrong/what I'm doing wrong would be much appreciated.

Also, I do understand that I could simply make previouslyNotedStr a substring of statsStr, starting from where I wish, and I've already tried that with success. I'm really just experimenting here.

  • `while (!stats.eof())` is a bad idea; `eof` may not be signalled until you have already tried to read past the end of the file. SO if your file ends in a newline you may get a bogus blank line. – M.M Aug 20 '14 at 20:20
  • @MattMcNabb I see. Do you suggest a different method? – Jacque Marliin Aug 20 '14 at 20:23
  • Yes, see Thomas Matthews' answer. In general, read until the read operation you are attempting fails. – M.M Aug 20 '14 at 20:25

2 Answers2

2

The VisualC++ tag means you are on windows. On Windows the end of line takes two characters (\r\n). When you read the file in a string at a time, this end-of-line sequence is treated as a delimiter and you replace it with a single space character.

Therefore after you read the file you statsStr does not match the contents of the file. Every where there is a new line in the file you have replaced two characters with one. Hence when you use seekg to position yourself in the file based on numbers you got from the statsStr string, you end up in the wrong place.

Even if you get the new line handling correct, you will still encounter problems if the file contains two or more consecutive white space characters, because these will be collapsed into a single space character by your read loop.

Dale Wilson
  • 9,166
  • 3
  • 34
  • 52
  • That makes perfect sense. So I'm better off just always copying the contents of the file to a string, and using that string in place of the file rather than actually extracting specific phrases directly from the file, correct? – Jacque Marliin Aug 20 '14 at 20:09
1

You are reading the file word by word. There are better methods:

while (getline(stats, statsSTr)
{
  // An entire line is read into statsStr.
  std::string::size_type posn = statsStr.find("previouslyNoted=");
  // ...
}

By reading entire text lines into a string, there is no need to reposition the file.

Also, there is a white-space issue when reading by word. This will affect where you think the text is in the file. For example, white space is skipped, and there is no telling how many spaces, newlines or tabs were skipped.

By the way, don't even think about replacing the text in the same file. Replacement of text only works if the replacement text has the same length as the original text in the file. Write to a new file instead.

Edit 1:
A better method is to declare your key strings as array. This helps with positioning pointers within a string:

static const char key_text[] = "previouslyNoted=";
while (getline(stats, statsStr))
{
  std::string::size_type key_position = statsStr.find(key_text);
  std::string::size_type value_position = key_position + sizeof(key_text) - 1; // for the nul terminator.
  // value_position points to the character after the '='.
  // ...
}

You may want to save programming type by making your data file conform to an existing format, such as INI or XML, and using appropriate libraries to parse them.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154