CFile side effect: GetLength() seek EOF.

Help
Charmel
2011-08-28
2013-05-28
  • Charmel

    Charmel - 2011-08-28

    Hi David,

    I noticed CFile::GetLength have a bad side effect: it seek to the end of the file.

    I think the next definition is OK:

    DWORD CFile::GetLength()
    {
        return ::GetFileSize(m_hFile, NULL);
    }
    

    Also, it can be interesting to have "CMemoryFile".

    An idea I have used previously is to define a pure virtual file class:

    class CVirtualFile
    {
       virtual DWORD GetPosition() const=0;
    ...
    }
    class CFile: public CVirtualFile
    {
    ....
    }
    class CMemFile: public CVirtualFile
    {
    ....
    }
    

    Thanks for your clever Win32 library that I use regularly in my works now.

    Charles

     
  • David

    David - 2011-08-31

    Hi Charles,

    Thanks for reporting this bug.  I've submitted an update to fix this problem. You can download the updated code using Tortoise SVN if you wish.  The new code looks like this:

    inline ULONGLONG CFile::GetLength( ) const
    // Returns the length of the file in bytes.
    {
        assert(m_hFile);
        LONG High = 0;
    //  DWORD LowPos = SetFilePointer(m_hFile, 0, &High, FILE_END);
        DWORD LowPos = SetFilePointer(m_hFile, 0, &High, FILE_CURRENT);
        ULONGLONG Result = ((ULONGLONG)High << 32) + LowPos;
        return Result;
    }
    

    This code supports file sizes larger than a DWORD,

    I'll look into your other suggestions regarding CMemoryFile as well.

    Best regards,
    David

     
  • Charmel

    Charmel - 2011-09-02

    Hi David,

    I checked this last GetLength() definition. But there is still a problem (From Win32 help " If the SetFilePointer function succeeds, the return value is the low-order doubleword of the new file pointer.  ).

    The next definition works :

        inline ULONGLONG CFile::GetLength( ) const
        // Returns the length of the file in bytes.
        {
            assert(m_hFile);
            DWORD High = 0;
            DWORD LowPos = GetFileSize(m_hFile, &High);
            ULONGLONG Result = ((ULONGLONG)High << 32) + LowPos;
            return Result;
        }
    

    Thanks,
    Charles

     
  • David

    David - 2011-09-03

    Hi Charles,

    Yes the GetFileSize function would seem the obvious choice here, but I avoided it because Microsoft advises that this function is unreliable for large files. Here is a direct quote from the Microsoft's Platform Development Kit documentation:

    "The GetFileSize function retrieves the size of the specified file. The file size that can be reported by this function is limited to a DWORD value.

    To retrieve a file size that is larger than a DWORD value, use the GetFileSizeEx function. It is recommended that you use GetFileSizeEx unless you specifically need to support older operating systems on which GetFileSizeEx is not supported."

    This is why I rejected GetFileSize and used SetFilePointer instead. I suspect that GetFileSize might not have been implemented properly (at least for some of the older operating systems). The maximum file size that can be reported as a DWORD value is about 4 GBytes. It is not uncommon to have files larger than this now.

    I have adjusted the CFile::GetLength code again. It now looks like this:

    inline ULONGLONG CFile::GetLength( ) const
    // Returns the length of the file in bytes.
    {
        assert(m_hFile);
        LONG HighPosCur = 0;
        LONG HighPosEnd = 0;
    //  DWORD LowPos = SetFilePointer(m_hFile, 0, &High, FILE_END);
        DWORD LowPosCur = SetFilePointer(m_hFile, 0, &HighPosCur, FILE_CURRENT);
        DWORD LowPosEnd = SetFilePointer(m_hFile, 0, &HighPosEnd, FILE_END);
        SetFilePointer(m_hFile, LowPosCur, &HighPosCur, FILE_BEGIN);
        ULONGLONG Result = ((ULONGLONG)HighPosEnd << 32) + LowPosEnd;
        return Result;
    }
    

    Best regards,
    David

     
  • Charmel

    Charmel - 2011-09-27

    That last (not easy) definition works fine.
    Thank you, David.

     

Log in to post a comment.