3

I want to seek back to a known position in a file. Therefore I use ftell to save the position and later I use fseek to get back.

I know about the restrictions, to seek to a specific position. But this doesn't apply to my case. I have a known position and I want to return to it.

Here the test code I wrote, to simplify the problem. It just saves a position in the file. Reads a string, gets back and rereads the string. And I get an assert, because sometimes I get two different results.

#include "stdlib.h"
#include "crtdbg.h"

int main()
{
    FILE *fStream = nullptr;
    if (_tfopen_s(&fStream,_T("TestFTell.txt"), _T("rt,ccs=UTF-8")))
        return 0;

    TCHAR szBuffer1[256], szBuffer2[256];    
    for (;;)
    {
        auto pos = ftell(fStream);
        _ASSERT(pos!=-1);
        if (!_fgetts(szBuffer1, _countof(szBuffer1), fStream))
            break;
        auto retval1 = fseek(fStream,pos,SEEK_SET);
        _ASSERT(retval1!=-1);
        auto retval2 = _fgetts(szBuffer2, _countof(szBuffer2), fStream);
        _ASSERT(retval2!=0);
        _ASSERT(_tcscmp(szBuffer1, szBuffer2)==0);      
    }
    return 0;
}

The program is compiled for unicode use. The text file simply contains some lines, with some lines have UTF-8 chars. Here a test file.

I tested it in VS-2010, VS-2013, VS-2015. In all versions I get an ASSERT.

Is this a bug, or do I misunderstand ftell/fseek?

How can I return to a previous read position in the file?

Or did I discover a bug in the CRT?

PS: In VS-2010 I already filed a bug for this case. They wrote that it will be fixed. Seams that this was never fixed.

xMRi
  • 14,982
  • 3
  • 26
  • 59
  • 1
    The file position is not in general reliably for text streams. Extra bonus for decoding utf-8, it requires buffering file data. So ftell() returns a value that is too large. You'll have to stop trying to make it work. – Hans Passant Mar 22 '17 at 10:44
  • But the docs say nothing about it. And anyhow why? I am always running on a full line UTF-8 char boundary (newline). Why this shouldn't be save? Or did I miss something? – xMRi Mar 22 '17 at 10:54
  • This bit concerns me: _"The text file simply contains some lines, with some lines have UTF-8"_. Could you clarify, is the whole file UTF-8 or only parts of it? – Richard Critten Mar 22 '17 at 11:02
  • The whole file is UTF-8 but you see AFAIK only 1 line with chars using more than 1 char in UTF-8. So nearly all lines are simply 8bit per char or in other words chars in the ascii range. Sorry for the confusion. This file has currently no BOM and as you see I speficy the encoding by myself in the fopen. – xMRi Mar 22 '17 at 11:10
  • Must be a bug. Just calling GetLength() inside the loop is sufficient to repro the bug. GetLength itself saves the current position and restores it and do it in a wrong bad way. – xMRi Mar 22 '17 at 12:41
  • @xMRI You are wrong about the docs, since you are running this on Windows you need to look at these docs: https://msdn.microsoft.com/en-us/library/75yw9bf3(v=vs.100).aspx , it says quite a bit about seeking in text files. – nos Mar 22 '17 at 12:57
  • @nos: Tell me where I am wrong! Quote it is save to do this: "For streams opened in text mode, fseek and _fseeki64have limited use, because carriage return–linefeed translations can cause fseek and _fseeki64to produce unexpected results. The only fseek and _fseeki64operations guaranteed to work on streams opened in text mode are: Seeking with an offset of 0 relative to any of the origin values. Seeking from the beginning of the file with an offset value returned from a call to ftell when using fseekor _ftelli64when using_fseeki64." I am just doing the second case. – xMRi Mar 22 '17 at 13:04
  • You are not seeking with an offset of 0 except for the 1. iteration of your loop, and you are not seeking from the beginning of the file (you call fseek after the _fgetts() call, and _fgetts() advances the position so its no longer from the start of your file.) – nos Mar 22 '17 at 13:13
  • 1
    I am doing this "Seeking from the beginning of the file with an offset value returned from a call to ftell when using fseekor _ftelli64when using_fseeki64." What else? – xMRi Mar 22 '17 at 13:23
  • @xMRi What value does `fseek()` return? You may want to try setting [an invalid parameter handler](https://msdn.microsoft.com/en-us/library/ksazx244%28v=vs.100%29.aspx), even if just to see if whether or not gets called - if your invalid parameter handler does get called, you'll know something is wrong. You should also check the return value from your second `_fgetts()` call. – Andrew Henle Mar 22 '17 at 13:32
  • Echoing @AndrewHenle, to help debug this code, add `auto pos = ftell(fStream); assert(pos != -1);` and `int retval = fseek(fStream,pos,SEEK_SET); assert(retval ==0);` I'd also check the return value of `_fgetts(szBuffer2, _countof(szBuffer2), fStream);`. Adding these 3 checks will help narrow the issue. IOWs, with an I/O problem, check the return of _all_ I/O functions. – chux - Reinstate Monica Mar 22 '17 at 14:51
  • Changed the code sample above. All checks passes. No error at all. – xMRi Mar 23 '17 at 07:34

0 Answers0