#pragma once #include "String.StringView.hpp" using namespace ECOM::Utility::String::Literals; #include "Utility.Expected.tlh" //--------------------------------------------------------------------- // 关于共享模式 // FileBuffer类中定义共享模式 // Open函数中没有用缺省参数 // IFileStreamBuffer的 // OpenForRead函数中使用缺省参数 shareDenyNone,即允许各种共享 // OFileStreamBuffer的 // OpenForWrite函数中使用缺省参数 shareDenyWrite, 即不允许其它写操作 // OpenForAppend函数中使用缺省参数 shareDenyWrite, 即不允许其它写操作 // DICOMFileBuffer的 // OpenForRead函数中使用缺省参数 shareDenyWrite, 即不允许其它写操作 // OpenForWrite函数中使用缺省参数 shareExclusive, 即不允许其它任何操作, 其它读操作当然也不允许 //--------------------------------------------------------------------- //----------------------------------------------------------------------------- // FileStreamBase //----------------------------------------------------------------------------- class FileStreamBase { protected: using eiResult = ECOM::Utility::Expected ; static constexpr auto eiSuccess = ECOM::Utility::left (1); public: enum enShareMode { shareCompat = (int) 0x00000, shareExclusive = (int) 0x00010, shareDenyWrite = (int) 0x00020, shareDenyRead = (int) 0x00030, shareDenyNone = (int) 0x00040, }; FileStreamBase () { m_hFile = INVALID_HANDLE_VALUE; m_bEOF = true; } virtual ~FileStreamBase () { Close (); } FileStreamBase (const FileStreamBase & FS) = delete; FileStreamBase (FileStreamBase && from) { this->m_bEOF = from.m_bEOF; this->m_hFile = from.m_hFile; from.m_bEOF = true; from.m_hFile = INVALID_HANDLE_VALUE; } FileStreamBase & operator = (const FileStreamBase & OB) = delete; FileStreamBase & operator = (FileStreamBase && OB) = delete; public: virtual eiResult Open (const wchar_t * filename, enShareMode mode) = 0; virtual void Close (void) { CloseFile (); } void CloseFile (void); void SeekToBegin (void); UINT32 SeekToEnd (void); virtual LONG Seek (LONG lOff, UINT nFrom); virtual DWORD GetLength (void) const; virtual DWORD GetLengthMB (void) const; virtual DWORD GetPosition (void) const; enum SeekPosition { begin = 0x0, current = 0x1, end = 0x2 }; virtual bool IsEOF (void) const; protected: enum enOpenMode { enRead = 'R', enWrite = 'W', enAppend = 'A' }; eiResult DoOpenRW (PCWSTR FileName, enShareMode Mode, enOpenMode RWA); void OnError (DWORD errCode, PCWSTR FileName); protected: bool m_bEOF; HANDLE m_hFile; }; //-----------------------------------------------------------------------------/// // IFileStream Class, no-cache available //-----------------------------------------------------------------------------/// class IFileStream : public FileStreamBase { public: IFileStream () = default; IFileStream (const wchar_t * filename) { OpenForRead (filename); } ~IFileStream () { Close (); } IFileStream (const IFileStream& FS) = delete; IFileStream (IFileStream && from) : FileStreamBase (std::move (from)) {} IFileStream & operator = (const IFileStream & OB) = delete; IFileStream & operator = (IFileStream && OB) = delete; public: virtual eiResult Open (const wchar_t * filename, enShareMode mode) override { return OpenForRead (filename, mode); } eiResult Open (PCWSTR filename) { return OpenForRead (filename); } DWORD ReadFile (void * Data, int cbNumBytes); eiResult OpenForRead (const wchar_t * filename, enShareMode mode = shareDenyWrite); // return the new positon after seek inline UINT Kill (UINT Bytes) { return Seek (Bytes, current); } inline bool IsExist (const wchar_t * FileName) { bool rc = OpenForRead (FileName); Close (); return rc; } }; //-----------------------------------------------------------------------------/// // OFileStream Class, no-cache available //-----------------------------------------------------------------------------/// class OFileStream : public FileStreamBase { public: OFileStream () = default; OFileStream (const wchar_t * filename) { OpenForWrite (filename); } ~OFileStream () { Close (); } OFileStream (const OFileStream & FS) = delete; OFileStream (OFileStream && from) : FileStreamBase (std::move (from)) {} OFileStream & operator = (const OFileStream & OB) = delete; OFileStream & operator = (OFileStream && OB) = delete; public: virtual eiResult Open (const wchar_t * filename, enShareMode mode) override { return OpenForWrite (filename, mode); } eiResult Open (PCWSTR filename) { return OpenForWrite (filename); } DWORD WriteFile (const void * Data, int cbNumBytes); eiResult OpenForWrite (const wchar_t * filename, enShareMode mode = shareExclusive); eiResult OpenForAppend (const wchar_t * filename, enShareMode mode = shareExclusive); }; //-----------------------------------------------------------------------------/// // FileStreamBase //-----------------------------------------------------------------------------/// template std::enable_if_t <(sizeof (T) == sizeof (unsigned long long)), T> __LockedExch (volatile T * h, T v) { auto rc = InterlockedExchange (reinterpret_cast (h), reinterpret_cast (v)); return reinterpret_cast (rc); } template std::enable_if_t <(sizeof (T) == sizeof (unsigned long)), T> __LockedExch (volatile T * h, T v) { auto rc = InterlockedExchange (reinterpret_cast (h), reinterpret_cast (v)); return reinterpret_cast (rc); } inline void FileStreamBase::CloseFile (void) { auto fh = __LockedExch (& m_hFile, INVALID_HANDLE_VALUE); if (fh == INVALID_HANDLE_VALUE) return; CloseHandle (fh); // m_hFile = INVALID_HANDLE_VALUE; m_bEOF = true; } inline UINT32 FileStreamBase::SeekToEnd (void) { return Seek (0, end); } inline void FileStreamBase::SeekToBegin (void) { Seek (0, begin); } // return the new position after seek inline LONG FileStreamBase::Seek (LONG lOff, UINT nFrom) { if (m_hFile == INVALID_HANDLE_VALUE) return -1; LONG rc = -1; switch (nFrom) { case begin : rc = ::SetFilePointer (m_hFile, lOff, NULL, FILE_BEGIN); break; case current: rc = ::SetFilePointer (m_hFile, lOff, NULL, FILE_CURRENT); break; case end : rc = ::SetFilePointer (m_hFile, lOff, NULL, FILE_END); break; } if (rc == -1) return 0; return rc; } // 多少字节 inline DWORD FileStreamBase::GetLength (void) const { DWORD hi = 0; DWORD lo = GetFileSize (m_hFile, &hi); if (lo == -1) lo = 0; return lo; } // 多少 MB inline DWORD FileStreamBase::GetLengthMB (void) const { DWORD hi = 0; DWORD lo = GetFileSize (m_hFile, &hi); if (lo == -1) lo = 0; hi <<= 12; lo >>= 20; return hi + lo; } inline DWORD FileStreamBase::GetPosition (void) const { return ::SetFilePointer (m_hFile, 0, NULL, FILE_CURRENT); } inline bool FileStreamBase::IsEOF (void) const { return m_bEOF; } inline auto FileStreamBase::DoOpenRW (PCWSTR FileName, enShareMode Mode, enOpenMode RWA) -> eiResult { Close (); // map share mode DWORD dwShareMode = 0; switch (Mode) // 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; } DWORD dwAccess = GENERIC_READ; if (RWA == enOpenMode::enRead) dwAccess = GENERIC_READ; else if (RWA == enOpenMode::enWrite) dwAccess = GENERIC_WRITE; else if (RWA == enOpenMode::enAppend) dwAccess = GENERIC_WRITE; else assert (false); DWORD dwDisposition = OPEN_EXISTING; if (RWA == enOpenMode::enRead) dwDisposition = OPEN_EXISTING; else if (RWA == enOpenMode::enWrite) dwDisposition = CREATE_ALWAYS; else if (RWA == enOpenMode::enAppend) dwDisposition = OPEN_EXISTING; else assert (false); m_hFile = CreateFileW ( FileName, dwAccess, dwShareMode, NULL, dwDisposition, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (m_hFile == INVALID_HANDLE_VALUE) { auto ec = GetLastError (); OnError (ec, FileName); SetLastError (ec); // return false; return ECOM::Utility::Error::OS::Windows::Make (ec); } m_bEOF = false; return eiSuccess; } //-----------------------------------------------------------------------------/// // IFileBuffer //-----------------------------------------------------------------------------/// inline auto IFileStream::OpenForRead (const wchar_t * filename, enShareMode Mode) -> eiResult { return DoOpenRW (filename, Mode, enOpenMode::enRead); } inline DWORD IFileStream::ReadFile (void * Data, int Length) { DWORD cbRead = 0; if (! ::ReadFile (m_hFile, Data, Length, & cbRead, NULL)) { #ifdef _DEBUG DWORD error = GetLastError (); #endif FileStreamBase::m_bEOF = true; return 0; } if (! cbRead) { FileStreamBase::m_bEOF = true; return 0; } return cbRead; } //-----------------------------------------------------------------------------/// // OFileStream //-----------------------------------------------------------------------------/// inline auto OFileStream::OpenForWrite (const wchar_t * filename, enShareMode Mode) -> eiResult { return DoOpenRW (filename, Mode, enOpenMode::enWrite); } inline auto OFileStream::OpenForAppend (const wchar_t * filename, enShareMode Mode) -> eiResult { auto rc = DoOpenRW (filename, Mode, enOpenMode::enAppend); if (! rc) rc = DoOpenRW (filename, Mode, enOpenMode::enWrite); if (! rc) return rc; SeekToEnd (); return eiSuccess; } inline DWORD OFileStream::WriteFile (const void * Data, int Length) { if (Length <= 0) return 0; DWORD cbWrite = 0; if (! ::WriteFile (m_hFile, Data, Length, & cbWrite, NULL)) { FileStreamBase::m_bEOF = true; return 0; } if (! cbWrite) { FileStreamBase::m_bEOF = true; return 0; } return cbWrite; } inline const IFileStream & operator >> (const IFileStream & IFS, std::string & s) { auto len = IFS.GetLength (); if (len <= 0) return IFS; s.resize (len); auto pc = s.data (); const_cast (IFS).ReadFile (pc, len); return IFS; } inline const OFileStream & operator << (const OFileStream & OFS, const std::string_view & s) { const_cast (OFS).WriteFile (s.data (), static_cast (s.size ())); return OFS; } inline const OFileStream & operator << (const OFileStream & OFS, const std::string & s) { const_cast (OFS).WriteFile (s.data (), static_cast (s.size ())); return OFS; } #ifdef DSTRING_API // 用 const 是为了解决如下语句的编译错误: IFileStream (FN) >> strXMLImageTag; //inline IFileStream & operator >> (IFileStream & IFS, eSTR::DString & s) inline const IFileStream & operator >> (const IFileStream & IFS, eSTR::DString & s) { auto len = IFS.GetLength (); if (len <= 0) return IFS; auto pc = s.GetBufferSetLength (len); const_cast (IFS).ReadFile (pc, len); return IFS; } inline const OFileStream & operator << (const OFileStream & OFS, const eSTR::DStringView & s) { const_cast (OFS).WriteFile (s, s.GetLength ()); return OFS; } inline const OFileStream & operator << (const OFileStream & OFS, const eSTR::DString & s) { const_cast (OFS).WriteFile (s, s.GetByteLength ()); return OFS; } #endif #ifdef WSTRING_API inline const IFileStream & operator >> (const IFileStream & IFS, eSTR::WString & s) { auto len = IFS.GetLength (); if (len <= 0) return IFS; auto pc = s.GetBufferSetLength (len/2); const_cast (IFS).ReadFile (pc, len); return IFS; } inline const OFileStream & operator << (const OFileStream & OFS, const eSTR::WStringView & s) { const_cast (OFS).WriteFile (s, s.GetLength () << 1); return OFS; } inline const OFileStream & operator << (const OFileStream & OFS, const eSTR::WString & s) { const_cast (OFS).WriteFile (s, s.GetByteLength ()); return OFS; } #endif #ifdef __TmplBlockBuffer__ inline const IFileStream & operator >> (const IFileStream & IFS, BlockBuffer & s) { auto len = IFS.GetLength (); if (len <= 0) return IFS; auto pc = s.GetBufferSetCount (len); const_cast (IFS).ReadFile (pc, len); return IFS; } inline const OFileStream & operator << (const OFileStream & OFS, const BlockBuffer & s) { const_cast (OFS).WriteFile (s, s.GetNbOfBytes ()); return OFS; } inline const IFileStream & operator >> (const IFileStream & IFS, OBlockBuffer & s) { auto len = IFS.GetLength (); if (len <= 0) return IFS; auto pc = s.GetBufferSetCount (len); const_cast (IFS).ReadFile (pc, len); return IFS; } inline const OFileStream & operator << (const OFileStream & OFS, const OBlockBuffer & s) { const_cast (OFS).WriteFile (s, s.GetNbOfBytes ()); return OFS; } #endif #ifdef __M_LOG_LOG4CPP__ inline void FileStreamBase::OnError (DWORD errCode, PCWSTR FileName) { mLog::Error ("Failed at FileStreamBase.DoOpenRW, {$} FileName : <{$}>"_sv, mLog::ErrorCodeToString (errCode), FileName); } #else inline void FileStreamBase::OnError (DWORD errCode, PCWSTR FileName) { } #endif