我正在使用Visual C++2008。在VC++ 2008中,CFile
支持2 ^ 64个大文件。所以我认为CStdioFile
也应该支持。
但是,在大于2GB的文件上使用CStdioFile::GetLength()
时,我得到了CFileException
,下面是代码片段:
void CTestCStdioFileDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
CStdioFile MyFile;
CString strLine;
ULONGLONG uLength;
strLine = _T("This is a line.");
if (MyFile.Open(_T("C:\\Temp\\MyTest.dat"), CFile::modeCreate | CFile::modeWrite | CFile::shareExclusive | CFile::typeBinary))
{
for (UINT uIndex = 0; uIndex = 200000000; uIndex ++)
{
MyFile.WriteString(strLine);
uLength = MyFile.GetLength();
}
MyFile.Close();
}
}
跟踪到
CStdio::GetLength()
后,我发现以下代码片段将引发异常,如下所示: nCurrent = ftell(m_pStream); -> This will return -1
if (nCurrent == -1)
AfxThrowFileException(CFileException::invalidFile, _doserrno,
m_strFileName);
令人惊讶的是
CStdioFile
仍然使用ftell
而不是_ftelli64
来处理流。然后,我在文档中搜索
CStdioFile
,在CStdioFile::GetLength
上找不到任何文档,唯一相关的是https://docs.microsoft.com/en-us/cpp/mfc/reference/cstdiofile-class?view=vs-2019#seek,它要求我查看fseek
文档。但是在fseek
文档中,我仍然找不到与文件大小限制有关的任何内容。最后,我找到了一个第三方站点,该站点指示
CStdioFile::GetLength
包含错误:http://www.flounder.com/msdn_documentation_errors_and_omissions.htm#CStdioFile::GetLength,但未提供解决方案。除此之外,几乎没有关于
CStdioFile
2GB限制的任何问题或帖子。真是奇怪我尝试检查iN VC++ 2017的
CStdioFile
的源代码,它与2008年的源代码相同。那么,是否有一个无需重写整个
CStdioFile
类的简单解决方案? 最佳答案
CStdioFile的存在主要是出于以下一个原因:constructor带有FILE*
参数。此类的目的是包装C运行时file并通过CFile
兼容的接口(interface)公开它。该实现继承了所有C运行时限制,尤其是2GB的文件大小限制。
为了解决这个问题,有几种选择:
CStdioFile
。除非您与(旧式)C代码连接,否则没有显着理由使用它。CStdioFile
和override
派生一个显示文件相对偏移的所有类成员的自定义实现(GetPosition()
,GetLength()
,Seek()
)。所有其他类成员均不受影响,可以简单地继承。 (注意:在实现GetLength()
时,请确保恢复当前文件指针。)Microsoft提供了对其C运行时的扩展,该扩展提供了64位宽的偏移量(_ftelli64和_fseeki64)。
如果需要使用选项2,可以将以下对
CStdioFile
的扩展用作支持2GB以上文件的直接替代。CStdioFileExt.h:
#pragma once
#include <afx.h>
class CStdioFileExt : public CStdioFile
{
DECLARE_DYNAMIC(CStdioFileExt)
public:
ULONGLONG GetPosition() const override;
ULONGLONG GetLength() const override;
ULONGLONG Seek(LONGLONG lOff, UINT nFrom) override;
};
CStdioFileExt.cpp:#include "CStdioFileExt.h"
ULONGLONG CStdioFileExt::GetPosition() const
{
ASSERT_VALID(this);
ASSERT(m_pStream != NULL);
auto const pos = _ftelli64(m_pStream);
if (pos == -1L)
AfxThrowFileException(CFileException::invalidFile, _doserrno, m_strFileName);
return static_cast<ULONGLONG>(pos);
}
ULONGLONG CStdioFileExt::GetLength() const
{
ASSERT_VALID(this);
auto const nCurrent = _ftelli64(m_pStream);
if (nCurrent == -1L)
AfxThrowFileException(CFileException::invalidFile, _doserrno, m_strFileName);
auto nResult = _fseeki64(m_pStream, 0, SEEK_END);
if (nResult != 0)
AfxThrowFileException(CFileException::badSeek, _doserrno, m_strFileName);
auto const nLength = _ftelli64(m_pStream);
if (nLength == -1L)
AfxThrowFileException(CFileException::invalidFile, _doserrno, m_strFileName);
nResult = _fseeki64(m_pStream, nCurrent, SEEK_SET);
if (nResult != 0)
AfxThrowFileException(CFileException::badSeek, _doserrno, m_strFileName);
return static_cast<ULONGLONG>(nLength);
}
ULONGLONG CStdioFileExt::Seek(LONGLONG lOff, UINT nFrom)
{
ASSERT_VALID(this);
ASSERT(nFrom == begin || nFrom == end || nFrom == current);
ASSERT(m_pStream != NULL);
if (_fseeki64(m_pStream, lOff, nFrom) != 0)
AfxThrowFileException(CFileException::badSeek, _doserrno, m_strFileName);
auto const pos = _ftelli64(m_pStream);
return static_cast<ULONGLONG>(pos);
}
IMPLEMENT_DYNAMIC(CStdioFileExt, CStdioFile)
关于c++ - CStdioFile无法使用大于2GB的文件?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/62097271/