2010-7-15 10:21:25
MFC CFile
class CFile : public CObject
{
DECLARE_DYNAMIC(CFile)
public:
// Flag values
enum OpenFlags {
modeRead = (int) 0x00000,
modeWrite = (int) 0x00001,
modeReadWrite = (int) 0x00002,
shareCompat = (int) 0x00000,
shareExclusive = (int) 0x00010,
shareDenyWrite = (int) 0x00020,
shareDenyRead = (int) 0x00030,
shareDenyNone = (int) 0x00040,
modeNoInherit = (int) 0x00080,
modeCreate = (int) 0x01000,
modeNoTruncate = (int) 0x02000,
typeText = (int) 0x04000, // typeText and typeBinary are
typeBinary = (int) 0x08000, // used in derived classes only
osNoBuffer = (int) 0x10000,
osWriteThrough = (int) 0x20000,
osRandomAccess = (int) 0x40000,
osSequentialScan = (int) 0x80000,
};
enum Attribute {
normal = 0x00,
readOnly = 0x01,
hidden = 0x02,
system = 0x04,
volume = 0x08,
directory = 0x10,
archive = 0x20
};
enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 };
static AFX_DATA const HANDLE hFileNull;
// Constructors
CFile();
CFile(HANDLE hFile);
CFile(LPCTSTR lpszFileName, UINT nOpenFlags);
// Attributes
HANDLE m_hFile;
operator HANDLE() const;
virtual ULONGLONG GetPosition() const;
BOOL GetStatus(CFileStatus& rStatus) const;
virtual CString GetFileName() const;
virtual CString GetFileTitle() const;
virtual CString GetFilePath() const;
virtual void SetFilePath(LPCTSTR lpszNewName);
// Operations
virtual BOOL Open(LPCTSTR lpszFileName, UINT nOpenFlags,
CFileException* pError = NULL);
static void PASCAL Rename(LPCTSTR lpszOldName,
LPCTSTR lpszNewName);
static void PASCAL Remove(LPCTSTR lpszFileName);
static BOOL PASCAL GetStatus(LPCTSTR lpszFileName,
CFileStatus& rStatus);
static void PASCAL SetStatus(LPCTSTR lpszFileName,
const CFileStatus& status);
ULONGLONG SeekToEnd();
void SeekToBegin();
// Overridables
#ifndef _WIN32_WCE // Unsupported feature
virtual CFile* Duplicate() const;
#endif // !_WIN32_WCE
virtual ULONGLONG Seek(LONGLONG lOff, UINT nFrom);
virtual void SetLength(ULONGLONG dwNewLen);
virtual ULONGLONG GetLength() const;
virtual UINT Read(void* lpBuf, UINT nCount);
virtual void Write(const void* lpBuf, UINT nCount);
#ifndef _WIN32_WCE // Unsupported Win32 API call
virtual void LockRange(ULONGLONG dwPos, ULONGLONG dwCount);
virtual void UnlockRange(ULONGLONG dwPos, ULONGLONG dwCount);
#endif // !_WIN32_WCE
virtual void Abort();
virtual void Flush();
virtual void Close();
// Implementation
public:
virtual ~CFile();
#ifdef _DEBUG
virtual void AssertValid() const;
#ifndef _WIN32_WCE
virtual void Dump(CDumpContext& dc) const;
#endif // !_WIN32_WCE
#endif
enum BufferCommand { bufferRead, bufferWrite, bufferCommit, bufferCheck };
enum BufferFlags
{
bufferDirect = 0x01,
bufferBlocking = 0x02
};
virtual UINT GetBufferPtr(UINT nCommand, UINT nCount = 0,
void** ppBufStart = NULL, void** ppBufMax = NULL);
protected:
BOOL m_bCloseOnDelete;
CString m_strFileName;
};
const HANDLE CFile::hFileNull = INVALID_HANDLE_VALUE;
CFile::CFile()
{
m_hFile = INVALID_HANDLE_VALUE;
m_bCloseOnDelete = FALSE;
}
CFile::CFile(HANDLE hFile)
{
ASSERT(hFile != INVALID_HANDLE_VALUE);
#ifdef _DEBUG
DWORD dwFlags=0;
ASSERT(GetHandleInformation(hFile,&dwFlags) != 0 );
#endif
m_hFile = hFile;
m_bCloseOnDelete = FALSE;
}
CFile::CFile(LPCTSTR lpszFileName, UINT nOpenFlags)
{
ASSERT(AfxIsValidString(lpszFileName));
m_hFile = INVALID_HANDLE_VALUE;
CFileException e;
if (!Open(lpszFileName, nOpenFlags, &e))
AfxThrowFileException(e.m_cause, e.m_lOsError, e.m_strFileName);
}
CFile::~CFile()
{
AFX_BEGIN_DESTRUCTOR
if (m_hFile != INVALID_HANDLE_VALUE && m_bCloseOnDelete)
Close();
AFX_END_DESTRUCTOR
}
CFile* CFile::Duplicate() const
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
CFile* pFile = new CFile();
HANDLE hFile;
if (!::DuplicateHandle(::GetCurrentProcess(), m_hFile,
::GetCurrentProcess(), &hFile, 0, FALSE, DUPLICATE_SAME_ACCESS))
{
delete pFile;
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
}
pFile->m_hFile = hFile;
ASSERT(pFile->m_hFile != INVALID_HANDLE_VALUE);
pFile->m_bCloseOnDelete = m_bCloseOnDelete;
return pFile;
}
BOOL CFile::Open(LPCTSTR lpszFileName, UINT nOpenFlags,
CFileException* pException)
{
ASSERT_VALID(this);
ASSERT(AfxIsValidString(lpszFileName));
ASSERT(pException == NULL ||
AfxIsValidAddress(pException, sizeof(CFileException)));
ASSERT((nOpenFlags & typeText) == 0); // text mode not supported
// shouldn't open an already open file (it will leak)
ASSERT(m_hFile == INVALID_HANDLE_VALUE);
// CFile objects are always binary and CreateFile does not need flag
nOpenFlags &= ~(UINT)typeBinary;
m_bCloseOnDelete = FALSE;
m_hFile = INVALID_HANDLE_VALUE;
m_strFileName.Empty();
TCHAR szTemp[_MAX_PATH];
if (lpszFileName != NULL && SUCCEEDED(StringCchLength(lpszFileName, _MAX_PATH, NULL)) )
{
if( _AfxFullPath2(szTemp, lpszFileName,pException) == FALSE )
return FALSE;
}
else
{
// user passed in a buffer greater then _MAX_PATH
if (pException != NULL)
{
pException->m_cause = CFileException::badPath;
pException->m_strFileName = lpszFileName;
}
return FALSE; // path is too long
}
m_strFileName = szTemp;
ASSERT(shareCompat == 0);
// map read/write mode
ASSERT((modeRead|modeWrite|modeReadWrite) == 3);
DWORD dwAccess = 0;
switch (nOpenFlags & 3)
{
case modeRead:
dwAccess = GENERIC_READ;
break;
case modeWrite:
dwAccess = GENERIC_WRITE;
break;
case modeReadWrite:
dwAccess = GENERIC_READ | GENERIC_WRITE;
break;
default:
ASSERT(FALSE); // invalid share mode
}
// map share mode
DWORD dwShareMode = 0;
switch (nOpenFlags & 0x70) // map compatibility mode to exclusive
{
default:
ASSERT(FALSE); // invalid share mode?
case shareCompat:
case shareExclusive:
dwShareMode = 0;
break;
case shareDenyWrite:
dwShareMode = FILE_SHARE_READ;
break;
case shareDenyRead:
dwShareMode = FILE_SHARE_WRITE;
break;
case shareDenyNone:
dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ;
break;
}
// Note: typeText and typeBinary are used in derived classes only.
// map modeNoInherit flag
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = (nOpenFlags & modeNoInherit) == 0;
// map creation flags
DWORD dwCreateFlag;
if (nOpenFlags & modeCreate)
{
if (nOpenFlags & modeNoTruncate)
dwCreateFlag = OPEN_ALWAYS;
else
dwCreateFlag = CREATE_ALWAYS;
}
else
dwCreateFlag = OPEN_EXISTING;
// special system-level access flags
// Random access and sequential scan should be mutually exclusive
ASSERT((nOpenFlags&(osRandomAccess|osSequentialScan)) != (osRandomAccess|
osSequentialScan) );
DWORD dwFlags = FILE_ATTRIBUTE_NORMAL;
if (nOpenFlags & osNoBuffer)
dwFlags |= FILE_FLAG_NO_BUFFERING;
if (nOpenFlags & osWriteThrough)
dwFlags |= FILE_FLAG_WRITE_THROUGH;
if (nOpenFlags & osRandomAccess)
dwFlags |= FILE_FLAG_RANDOM_ACCESS;
if (nOpenFlags & osSequentialScan)
dwFlags |= FILE_FLAG_SEQUENTIAL_SCAN;
// attempt file creation
HANDLE hFile = ::CreateFile(lpszFileName, dwAccess, dwShareMode, &sa,
dwCreateFlag, dwFlags, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
_AfxFillExceptionInfo(pException,lpszFileName);
return FALSE;
}
m_hFile = hFile;
m_bCloseOnDelete = TRUE;
return TRUE;
}
UINT CFile::Read(void* lpBuf, UINT nCount)
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
if (nCount == 0)
return 0; // avoid Win32 "null-read"
ASSERT(lpBuf != NULL);
ASSERT(AfxIsValidAddress(lpBuf, nCount));
DWORD dwRead;
if (!::ReadFile(m_hFile, lpBuf, nCount, &dwRead, NULL))
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
return (UINT)dwRead;
}
void CFile::Write(const void* lpBuf, UINT nCount)
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
if (nCount == 0)
return; // avoid Win32 "null-write" option
ASSERT(lpBuf != NULL);
ASSERT(AfxIsValidAddress(lpBuf, nCount, FALSE));
DWORD nWritten;
if (!::WriteFile(m_hFile, lpBuf, nCount, &nWritten, NULL))
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
if (nWritten != nCount)
AfxThrowFileException(CFileException::diskFull, -1, m_strFileName);
}
ULONGLONG CFile::Seek(LONGLONG lOff, UINT nFrom)
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
ASSERT(nFrom == begin || nFrom == end || nFrom == current);
ASSERT(begin == FILE_BEGIN && end == FILE_END && current == FILE_CURRENT);
LARGE_INTEGER liOff;
liOff.QuadPart = lOff;
liOff.LowPart = ::SetFilePointer(m_hFile, liOff.LowPart, &liOff.HighPart,
(DWORD)nFrom);
if (liOff.LowPart == (DWORD)-1)
if (::GetLastError() != NO_ERROR)
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
return liOff.QuadPart;
}
ULONGLONG CFile::GetPosition() const
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
LARGE_INTEGER liPos;
liPos.QuadPart = 0;
liPos.LowPart = ::SetFilePointer(m_hFile, liPos.LowPart, &liPos.HighPart , FILE_CURRENT);
if (liPos.LowPart == (DWORD)-1)
if (::GetLastError() != NO_ERROR)
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
return liPos.QuadPart;
}
void CFile::Flush()
{
ASSERT_VALID(this);
if (m_hFile == INVALID_HANDLE_VALUE)
return;
if (!::FlushFileBuffers(m_hFile))
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
}
void CFile::Close()
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
BOOL bError = FALSE;
if (m_hFile != INVALID_HANDLE_VALUE)
bError = !::CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
m_bCloseOnDelete = FALSE;
m_strFileName.Empty();
if (bError)
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
}
void CFile::Abort()
{
ASSERT_VALID(this);
if (m_hFile != INVALID_HANDLE_VALUE)
{
// close but ignore errors
::CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
m_strFileName.Empty();
}
void CFile::LockRange(ULONGLONG dwPos, ULONGLONG dwCount)
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
ULARGE_INTEGER liPos;
ULARGE_INTEGER liCount;
liPos.QuadPart = dwPos;
liCount.QuadPart = dwCount;
if (!::LockFile(m_hFile, liPos.LowPart, liPos.HighPart, liCount.LowPart,
liCount.HighPart))
{
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
}
}
void CFile::UnlockRange(ULONGLONG dwPos, ULONGLONG dwCount)
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
ULARGE_INTEGER liPos;
ULARGE_INTEGER liCount;
liPos.QuadPart = dwPos;
liCount.QuadPart = dwCount;
if (!::UnlockFile(m_hFile, liPos.LowPart, liPos.HighPart, liCount.LowPart,
liCount.HighPart))
{
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
}
}
void CFile::SetLength(ULONGLONG dwNewLen)
{
ASSERT_VALID(this);
ASSERT(m_hFile != INVALID_HANDLE_VALUE);
Seek(dwNewLen, (UINT)begin);
if (!::SetEndOfFile(m_hFile))
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
}
ULONGLONG CFile::GetLength() const
{
ASSERT_VALID(this);
ULARGE_INTEGER liSize;
liSize.LowPart = ::GetFileSize(m_hFile, &liSize.HighPart);
if (liSize.LowPart == INVALID_FILE_SIZE)
if (::GetLastError() != NO_ERROR)
CFileException::ThrowOsError((LONG)::GetLastError(), m_strFileName);
return liSize.QuadPart;
}
// CFile does not support direct buffering (CMemFile does)
UINT CFile::GetBufferPtr(UINT nCommand, UINT /*nCount*/,
void** /*ppBufStart*/, void** /*ppBufMax*/)
{
ASSERT(nCommand == bufferCheck);
UNUSED(nCommand); // not used in retail build
return 0; // no support
}
void PASCAL CFile::Rename(LPCTSTR lpszOldName, LPCTSTR lpszNewName)
{
if (!::MoveFile((LPTSTR)lpszOldName, (LPTSTR)lpszNewName))
CFileException::ThrowOsError((LONG)::GetLastError(), lpszOldName);
}
void PASCAL CFile::Remove(LPCTSTR lpszFileName)
{
if (!::DeleteFile((LPTSTR)lpszFileName))
CFileException::ThrowOsError((LONG)::GetLastError(), lpszFileName);
}