HOWTO: Read From or Write To CFile From Buffer Larger Than 64KID: Q92860
|
In certain situations, an application can read or write a file larger
than 65,535 bytes using one large buffer that is usually allocated by
calling the GlobalAlloc() function. Traditionally, to use one buffer
the application must perform huge pointer manipulations on a buffer
pointer and call the _lread() and _lwrite() functions (provided by
Microsoft Windows) in a loop.
In an application developed with the Microsoft Foundation Classes, an
attempt to use a huge pointer with the CFile::Read() or CFile::Write()
functions fails at the following assertion:
ASSERT(AfxIsValidAddress(lpBuf, nCount));
The CFile::Read() and CFile::Write() functions each contain the
ASSERT.
Because the AfxIsValidAddress() function was not designed to work with
huge pointers, the ASSERT fails when the application specifies a huge
pointer.
Version 2.0 and later of the Microsoft Foundation Classes provides two
functions, CFile::ReadHuge() and CFile::WriteHuge() that can accept
huge pointers. Even though these functions are not listed in the
online or printed documentation, the DIBLOOK sample application uses
these functions. The AFX.H header file provides prototypes for these
CFile member functions.
In code developed with version 1.0 of the Microsoft Foundation
Classes, the method illustrated below demonstrates working around this
limitation. The Microsoft Foundation Classes Object Linking and
Embedding (OLE) Stream Get() and Put() functions implement this
method. For more information, please refer to the source code for
these functions in the OLECLI.CPP file in the MFC\SRC directory.
The text below provides the ReadHuge() and WriteHuge() functions to
read from and write to a CFile object from a very large buffer. These
functions use the _HugeCalcSize() helper function to determine whether
a memory read or write crosses a segment boundary.
A second code example demonstrates using the WriteHuge() function.
//
// Prototypes
//
static UINT _HugeCalcSize(DWORD cbTotal, const void FAR* lpStart);
DWORD ReadHuge(void FAR* lpBuffer, DWORD dwCount, CFile* file);
void WriteHuge(const void FAR* lpBuffer, DWORD dwCount, CFile* file);
//
// Functions Definitions
//
static UINT _HugeCalcSize(DWORD cbTotal, const void FAR* lpStart)
{
// Return Size to Read/Write
// (16K max unless limited by segment bounds)
//
DWORD cb = 0x10000L - _AFX_FP_OFF(lpStart);
if (cb > cbTotal)
cb = cbTotal;
return (cb > 16384) ? 16384 : (UINT)cb;
}
DWORD ReadHuge(void FAR* lpBuffer, DWORD dwCount, CFile* file)
{
ASSERT_VALID(file);
DWORD dwToRead = dwCount;
while (dwToRead > 0)
{
UINT nRead = _HugeCalcSize(dwToRead, lpBuffer);
if (file->Read(lpBuffer, nRead) < nRead)
return ((dwCount - dwToRead) + nRead);
dwToRead -= nRead;
lpBuffer = ((BYTE _huge*)lpBuffer) + nRead;
}
return dwCount;
}
void WriteHuge(const void FAR* lpBuffer, DWORD dwCount, CFile* file)
{
ASSERT_VALID(file);
DWORD dwToWrite = dwCount;
while (dwToWrite > 0)
{
UINT nWrite = _HugeCalcSize(dwToWrite, lpBuffer);
file->Write(lpBuffer, nWrite);
dwToWrite -= nWrite;
lpBuffer = ((const BYTE _huge*)lpBuffer) + nWrite;
}
}
// WriteTest():
//
// Uses WriteHuge() to write a buffer to disk using the CFile
// class from Microsoft Foundation Classes version 1.0.
//
void WriteTest(CString strFileName, DWORD length)
{
HGLOBAL hBuff = GlobalAlloc(GHND, length);
ASSERT(hBuff != NULL);
char FAR* pBuff = (char FAR*) GlobalLock(hBuff);
CFile* pFile = new CFile(strFileName, CFile::modeCreate |
CFile::modeWrite | CFile::typeBinary);
DWORD index;
// Fill Buffer with Test Pattern
//
for (index = 0; index < length; index++)
{
*(pBuff+index) = (char) (index % 0x00000100);
}
// Write Buffer to Disk
//
::WriteHuge(pBuff, length, pFile);
pFile->Close();
delete pFile;
GlobalUnlock(hBuff);
GlobalFree(hBuff);
}
Additional query words:
Keywords : kb16bitonly kbFileIO kbMFC kbVC
Version : 1.0 1.5 1.51 1.52 7.0
Platform :
Issue type : kbhowto
Last Reviewed: August 2, 1999