<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>fstream behavior</title>
		<link>http://www.allegro.cc/forums/view/594765</link>
		<description>Allegro.cc Forum Thread</description>
		<webMaster>matthew@allegro.cc (Matthew Leverton)</webMaster>
		<lastBuildDate>Thu, 17 Jan 2008 10:53:37 +0000</lastBuildDate>
	</channel>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I can&#39;t understand why fstream sets the failbits when the file you try to open does not exist.  I ran into a strange problem today related to fstream in that if the failbit is set it&#39;s easy to run into an infinite loop:
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td>fstream fin<span class="k2">;</span></td></tr><tr><td class="number">2</td><td>fin.open<span class="k2">(</span><span class="s">"C:\some_file_that_does_not_exist.txt"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">3</td><td><span class="k1">if</span><span class="k2">(</span><span class="k3">!</span>fin.is_open<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span></td></tr><tr><td class="number">4</td><td><span class="k2">{</span></td></tr><tr><td class="number">5</td><td>   fin.open<span class="k2">(</span><span class="s">"C:\some_file_that_exists.txt"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">6</td><td><span class="k2">}</span></td></tr><tr><td class="number">7</td><td>&#160;</td></tr><tr><td class="number">8</td><td><span class="k1">if</span><span class="k2">(</span>fin.is_open<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span></td></tr><tr><td class="number">9</td><td><span class="k2">{</span></td></tr><tr><td class="number">10</td><td>    string tmp<span class="k2">;</span></td></tr><tr><td class="number">11</td><td>    <span class="k1">while</span><span class="k2">(</span><span class="k3">!</span>getline<span class="k2">(</span>fin, tmp<span class="k2">)</span>.eof<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span></td></tr><tr><td class="number">12</td><td>    <span class="k2">{</span></td></tr><tr><td class="number">13</td><td>         <span class="c">// Infinite loop!</span></td></tr><tr><td class="number">14</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">15</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>

The problem is that the first fin.open failed which set the failbit while the second fin.open succeeded but did not reset the failbits.  When you call getline it will never be able to read and therefore never hit the eof.  </p><p>Simple fix is to add fin.clear() before getline but it&#39;s not evident by the logic above that you must do that.  Shouldn&#39;t fstream reset the failbits if open succeeds?
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Steve Terry)</author>
		<pubDate>Wed, 16 Jan 2008 06:27:19 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I use a different check to see if the fstream is valid. Instead of using fstream.is_open() , I use either a boolean test with operator ! or a call to the fstream.good() function.
</p><div class="source-code"><div class="toolbar"></div><div class="inner"><table width="100%"><tbody><tr><td class="number">1</td><td>ofstream log_file<span class="k2">(</span><span class="s">".\\program_log.txt"</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">2</td><td>&#160;</td></tr><tr><td class="number">3</td><td><span class="c">// boolean</span></td></tr><tr><td class="number">4</td><td><span class="k1">if</span> <span class="k2">(</span><span class="k3">!</span>log_file<span class="k2">)</span> <span class="k2">{</span><span class="c">// couldn't open log properly , operator ! does same thing as ios::fail()</span></td></tr><tr><td class="number">5</td><td>  <span class="c">// decide whether to continue without log</span></td></tr><tr><td class="number">6</td><td><span class="k2">}</span></td></tr><tr><td class="number">7</td><td><span class="c">// good() method</span></td></tr><tr><td class="number">8</td><td><span class="k1">if</span> <span class="k2">(</span><span class="k3">!</span><span class="k2">(</span>log_file.good<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">9</td><td>  <span class="c">// see what the problem with the file is</span></td></tr><tr><td class="number">10</td><td>  <span class="k1">if</span> <span class="k2">(</span>log_file.fail<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span><span class="c">// if fail() returns true then either failbit set or badbit set</span></td></tr><tr><td class="number">11</td><td>    <span class="k1">if</span> <span class="k2">(</span><span class="k3">!</span>log_file.bad<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span></td></tr><tr><td class="number">12</td><td>      <span class="c">// fail bit set for log file</span></td></tr><tr><td class="number">13</td><td>      <span class="c">/// Try clearing state and repositioning stream</span></td></tr><tr><td class="number">14</td><td>      log_file.clear<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">15</td><td>      log_file.seekg<span class="k2">(</span><span class="n">0</span> , ios::beg<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">16</td><td>      log_file.seekp<span class="k2">(</span><span class="n">0</span> , ios::beg<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">17</td><td>    <span class="k2">}</span> <span class="k1">else</span> <span class="k2">{</span></td></tr><tr><td class="number">18</td><td>      <span class="c">// bad bit set for log file , and perhaps fail bit also</span></td></tr><tr><td class="number">19</td><td>      <span class="c">// bad bit means inoperable as far as I know , so quit</span></td></tr><tr><td class="number">20</td><td>    <span class="k2">}</span></td></tr><tr><td class="number">21</td><td>    </td></tr><tr><td class="number">22</td><td>  <span class="k2">}</span> <span class="k1">else</span> <span class="k2">{</span><span class="c">// if good() is false and if fail() is false , then eof() should be true</span></td></tr><tr><td class="number">23</td><td>    <span class="c">// just need to stop reading or reposition place in stream</span></td></tr><tr><td class="number">24</td><td>    <span class="c">// have to call clear to get rid of the eofbit state though</span></td></tr><tr><td class="number">25</td><td>    log_file.clear<span class="k2">(</span><span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">26</td><td>    log_file.seekg<span class="k2">(</span><span class="n">0</span> , ios::beg<span class="k2">)</span><span class="k2">;</span></td></tr><tr><td class="number">27</td><td>  <span class="k2">}</span></td></tr><tr><td class="number">28</td><td><span class="k2">}</span></td></tr></tbody></table></div></div><p>

It makes sense that if you open a new fstream that the failbit shouldn&#39;t be set since it hasn&#39;t actually failed , I think you&#39;re right about that.</p><p>- Append -<br />Actually , though , I understand why the failbit is set when opening a file doesn&#39;t work. You wouldn&#39;t want ios::good() to return true when a file failed to open would you? So I suppose it&#39;s their reasoning that the failbit should be cleared manually by the user but I still agree that if open is called , it should reset the bits itself. Assuming that they would use the ios::setstate function to set the state of the stream after attempting to open a file , then it would make sense that they would use ios::setstate(goodbit) if successful , but maybe they don&#39;t. Should be easy to test with something like :
</p><div class="source-code snippet"><div class="inner"><pre><span class="k1">bool</span> file_error_flag <span class="k3">=</span> <span class="k1">false</span><span class="k2">;</span>
fstream file<span class="k2">;</span>
file.open<span class="k2">(</span><span class="s">".\\nonexistentfile.txt"</span><span class="k2">)</span><span class="k2">;</span>
<span class="k1">if</span> <span class="k2">(</span>file.good<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span>
  cout <span class="k3">&lt;</span><span class="k3">&lt;</span> <span class="s">"File stream incorrectly reported as good when opening a non existent file"</span> <span class="k3">&lt;</span><span class="k3">&lt;</span> endl<span class="k2">;</span>
<span class="k2">}</span> <span class="k1">else</span> <span class="k2">{</span>
  file_error_flag <span class="k3">=</span> <span class="k1">true</span><span class="k2">;</span>
<span class="k2">}</span>
file.open<span class="k2">(</span><span class="s">".\\realfile.txt"</span><span class="k2">)</span><span class="k2">;</span>
<span class="k1">if</span> <span class="k2">(</span>file_error_flag<span class="k2">)</span> <span class="k2">{</span>
  <span class="k1">if</span> <span class="k2">(</span><span class="k3">!</span>file.good<span class="k2">(</span><span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span>
    cout <span class="k3">&lt;</span><span class="k3">&lt;</span> <span class="s">"File stream incorrectly reported as not good() when opening an actual file"</span> <span class="k3">&lt;</span><span class="k3">&lt;</span> endl<span class="k2">;</span>
  <span class="k2">}</span>
<span class="k2">}</span>
</pre></div></div><p>
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Edgar Reynaldo)</author>
		<pubDate>Wed, 16 Jan 2008 12:20:05 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Quote:</div><div class="quote"><p>
Simple fix is to add fin.clear() before getline but it&#39;s not evident by the logic above that you must do that. Shouldn&#39;t fstream reset the failbits if open succeeds?
</p></div></div><p>
It might be considered a &quot;sticky bit&quot; that you must explicitly clear.  Then you could detect errors indefinitely later, like glError() or fxam do.</p><p>[EDIT] glError() clears them as you fetch the errors.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Arthur Kalliokoski)</author>
		<pubDate>Thu, 17 Jan 2008 04:21:16 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title">Edgar Reynaldo said:</div><div class="quote"><p>
Actually , though , I understand why the failbit is set when opening a file doesn&#39;t work. You wouldn&#39;t want ios::good() to return true when a file failed to open would you?
</p></div></div><p>I agree that the failbit should be set when open() fails. But I think what Steve Terry is saying is that when the second open() succeeds it should unset the failbit. It is a new file, essentially a new instance of the whole fstream thing, and nothing has gone wrong yet - so the failbit should have been unset.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Karadoc ~~)</author>
		<pubDate>Thu, 17 Jan 2008 10:53:37 +0000</pubDate>
	</item>
</rss>
