//+------------------------------------------------------------------+ //| MetaTrader 5 API | //| Copyright 2000-2019, MetaQuotes Software Corp. | //| http://www.metaquotes.net | //+------------------------------------------------------------------+ #pragma once #include "MT5APIStr.h" //+------------------------------------------------------------------+ //| File operations wrapper class | //+------------------------------------------------------------------+ class CMTFile { public: static const UINT64 INVALID_POSITION; private: HANDLE m_file; public: CMTFile():m_file(INVALID_HANDLE_VALUE) {} virtual ~CMTFile() { Close(); } //--- file open bool Open(LPCWSTR lpFileName,const DWORD dwAccess,const DWORD dwShare,const DWORD dwCreationFlags,const DWORD dwAttributes=FILE_ATTRIBUTE_NORMAL); bool OpenRead(LPCWSTR lpFileName); bool OpenWrite(LPCWSTR lpFileName); //--- file close void Close(void); //--- file properties HANDLE Handle(void); bool IsOpen() const; UINT64 Size(void) const; static UINT64 Size(LPCWSTR path); FILETIME TimeCreate(void) const; FILETIME TimeLastAccess(void) const; FILETIME TimeLastModify(void) const; UINT64 CurrPos(void); //--- file operations DWORD Read(void *buffer,const DWORD length); DWORD Write(const void *buffer,const DWORD length); UINT64 Seek(const INT64 distance,const DWORD method); bool ChangeSize(const UINT64 size); bool Flush(); //--- files group operations static int FilesCopy(const CMTStr& path,const CMTStr& newpath,const CMTStr& mask,const bool subdir); //--- directory operations static bool DirectoryCreate(const CMTStr& path); static bool DirectoryRemove(const CMTStr& path); static bool DirectoryClean(const CMTStr& path,const CMTStr& mask); }; //+------------------------------------------------------------------+ //| Constant declaration | //+------------------------------------------------------------------+ const __declspec(selectany) UINT64 CMTFile::INVALID_POSITION=_UI64_MAX; //+------------------------------------------------------------------+ //| File open | //+------------------------------------------------------------------+ inline bool CMTFile::Open(LPCWSTR lpFileName,const DWORD dwAccess,const DWORD dwShare,const DWORD dwCreationFlags,const DWORD dwAttributes) { //--- close previous Close(); //--- check name and open if(lpFileName) m_file=CreateFileW(lpFileName,dwAccess,dwShare,NULL,dwCreationFlags,dwAttributes,NULL); //--- return return(m_file!=INVALID_HANDLE_VALUE); } //+------------------------------------------------------------------+ //| File open for read | //+------------------------------------------------------------------+ inline bool CMTFile::OpenRead(LPCWSTR lpFileName) { return Open(lpFileName,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,OPEN_EXISTING); } //+------------------------------------------------------------------+ //| File open for write | //+------------------------------------------------------------------+ inline bool CMTFile::OpenWrite(LPCWSTR lpFileName) { return Open(lpFileName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,CREATE_ALWAYS); } //+------------------------------------------------------------------+ //| File close | //+------------------------------------------------------------------+ inline void CMTFile::Close(void) { if(m_file!=INVALID_HANDLE_VALUE) { CloseHandle(m_file); m_file=INVALID_HANDLE_VALUE; } } //+------------------------------------------------------------------+ //| File handle | //+------------------------------------------------------------------+ inline HANDLE CMTFile::Handle(void) { return(m_file); } //+------------------------------------------------------------------+ //| Check file state | //+------------------------------------------------------------------+ inline bool CMTFile::IsOpen(void) const { return(m_file!=INVALID_HANDLE_VALUE); } //+------------------------------------------------------------------+ //| File size | //+------------------------------------------------------------------+ inline UINT64 CMTFile::Size() const { LARGE_INTEGER li={}; //--- check and receive if(m_file==INVALID_HANDLE_VALUE || !::GetFileSizeEx(m_file,&li)) return(0); //--- return result return((UINT64)li.QuadPart); } //+------------------------------------------------------------------+ //| File size | //+------------------------------------------------------------------+ inline UINT64 CMTFile::Size(LPCWSTR path) { LARGE_INTEGER li={}; WIN32_FILE_ATTRIBUTE_DATA fad; //--- receive file if(GetFileAttributesExW(path,GetFileExInfoStandard,&fad)) { li.LowPart =fad.nFileSizeLow; li.HighPart=(LONG)fad.nFileSizeHigh; } //--- return result return((UINT64)li.QuadPart); } //+------------------------------------------------------------------+ //| File creation time | //+------------------------------------------------------------------+ inline FILETIME CMTFile::TimeCreate() const { FILETIME ft={}; //--- check and receive if(m_file!=INVALID_HANDLE_VALUE) GetFileTime(m_file,&ft,NULL,NULL); //--- return result return(ft); } //+------------------------------------------------------------------+ //| File last access time | //+------------------------------------------------------------------+ inline FILETIME CMTFile::TimeLastAccess() const { FILETIME ft={}; //--- check and receive if(m_file!=INVALID_HANDLE_VALUE) GetFileTime(m_file,NULL,&ft,NULL); //--- return result return(ft); } //+------------------------------------------------------------------+ //| File last modify time | //+------------------------------------------------------------------+ inline FILETIME CMTFile::TimeLastModify() const { FILETIME ft={}; //--- check and receive if(m_file!=INVALID_HANDLE_VALUE) GetFileTime(m_file,NULL,NULL,&ft); //--- return result return(ft); } //+------------------------------------------------------------------+ //| File pointer position | //+------------------------------------------------------------------+ inline UINT64 CMTFile::CurrPos() { return(CMTFile::Seek(INT64(0),FILE_CURRENT)); } //+------------------------------------------------------------------+ //| File read | //+------------------------------------------------------------------+ inline DWORD CMTFile::Read(void *buffer,const DWORD length) { //--- check if(m_file==INVALID_HANDLE_VALUE || buffer==NULL || length<1) return(0); //--- read DWORD readed=0; if(ReadFile(m_file,buffer,length,&readed,NULL)==0) readed=0; //--- return return(readed); } //+------------------------------------------------------------------+ //| Write to file | //+------------------------------------------------------------------+ inline DWORD CMTFile::Write(const void *buffer,const DWORD length) { //--- check if(m_file==INVALID_HANDLE_VALUE || buffer==NULL || length<1) return(0); //--- write DWORD written=0; if(WriteFile(m_file,buffer,length,&written,NULL)==0) written=0; //--- return return(written); } //+------------------------------------------------------------------+ //| Seek file pointer | //+------------------------------------------------------------------+ inline UINT64 CMTFile::Seek(const INT64 distance,const DWORD method) { //--- check if(m_file==INVALID_HANDLE_VALUE) return(INVALID_POSITION); //--- fill and seek LARGE_INTEGER li={}; li.QuadPart=distance; li.LowPart=SetFilePointer(m_file,(LONG)li.LowPart,&li.HighPart,method); //--- check result if(li.LowPart==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) return(INVALID_POSITION); //--- return new file pointer position return((UINT64)li.QuadPart); } //+------------------------------------------------------------------+ //| Change file size | //+------------------------------------------------------------------+ inline bool CMTFile::ChangeSize(const UINT64 size) { return(CMTFile::Seek((INT64)size,FILE_BEGIN)==size && SetEndOfFile(m_file)); } //+------------------------------------------------------------------+ //| Flush file buffer | //+------------------------------------------------------------------+ inline bool CMTFile::Flush() { if(m_file!=INVALID_HANDLE_VALUE) return(::FlushFileBuffers(m_file)!=0); return(false); } //+------------------------------------------------------------------+ //| Copy files by mask | //+------------------------------------------------------------------+ inline int CMTFile::FilesCopy(const CMTStr& path,const CMTStr& newpath,const CMTStr& mask,const bool subdir) { CMTStr512 src,dst,name; HANDLE hSearch; WIN32_FIND_DATAW fnd; int count=0; //--- find files src.Format(L"%s\\%s",path.Str(),mask.Str()); if((hSearch=FindFirstFileW(src.Str(), &fnd))!=INVALID_HANDLE_VALUE) { do { //--- skip root directories if(CMTStr::Compare(fnd.cFileName,L".")==0 || CMTStr::Compare(fnd.cFileName,L"..")==0) continue; //--- directory? if(!(fnd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { //--- create source path src.Format(L"%s\\%s",path.Str(),fnd.cFileName); //--- create dst path dst.Format(L"%s\\%s",newpath.Str(),fnd.cFileName); //--- copy file if(::CopyFileW(src.Str(),dst.Str(),FALSE)!=FALSE) count++; } else if(subdir) { //--- create path src.Format(L"%s\\%s",path.Str(),fnd.cFileName); dst.Format(L"%s\\%s",newpath.Str(),fnd.cFileName); //--- create dst path DirectoryCreate(dst); //--- copy files count+=FilesCopy(src,dst,mask,subdir); } } while(FindNextFileW(hSearch,&fnd)!=0); //--- close handle FindClose(hSearch); } //--- return copied count return(count); } //+------------------------------------------------------------------+ //| Create directory with subdirectories | //+------------------------------------------------------------------+ inline bool CMTFile::DirectoryCreate(const CMTStr& path) { wchar_t *cp,temp[MAX_PATH]; //--- check directory if(GetFileAttributesW(path.Str())!=INVALID_FILE_ATTRIBUTES) return(true); //--- copy CMTStr::Copy(temp,path.Str()); //--- parse path and create directories for(cp=temp;*cp!=L'\0';cp++) if(*cp==L'\\') { *cp=L'\0'; if(GetFileAttributesW(temp)==INVALID_FILE_ATTRIBUTES) if(!::CreateDirectoryW(temp,NULL)) return(false); *cp=L'\\'; } //--- copy remainder if(GetFileAttributesW(temp)==INVALID_FILE_ATTRIBUTES) if(!::CreateDirectoryW(temp,NULL)) return(false); //--- ok return(true); } //+------------------------------------------------------------------+ //| Directory clean by mask | //+------------------------------------------------------------------+ inline bool CMTFile::DirectoryClean(const CMTStr& path,const CMTStr& mask) { HANDLE hSearch; WIN32_FIND_DATAW fnd; CMTStrPath tmp; bool res=true; //--- check if(path.Empty() || path.Len()<=3) return(false); //--- create path tmp.Format(L"%s\\%s",path.Str(),mask.Str()); //--- search if((hSearch=FindFirstFileW(tmp.Str(),&fnd))!=INVALID_HANDLE_VALUE) { do { //--- directory? if(fnd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { //--- skip root directories if(CMTStr::Compare(fnd.cFileName,L".")==0 || CMTStr::Compare(fnd.cFileName,L"..")==0) continue; //--- create directory path tmp.Format(L"%s\\%s",path.Str(),fnd.cFileName); //--- clean directory DirectoryClean(tmp,mask); //--- delete directory res=::RemoveDirectoryW(tmp.Str()) && res; } else { //--- create file path tmp.Format(L"%s\\%s",path.Str(),fnd.cFileName); //--- delete file res=::DeleteFileW(tmp.Str()) && res; } } while(FindNextFileW(hSearch,&fnd)); //--- close handle FindClose(hSearch); } //--- result return(res); } //+------------------------------------------------------------------+ //| Full directory remove | //+------------------------------------------------------------------+ inline bool CMTFile::DirectoryRemove(const CMTStr& path) { return(DirectoryClean(path,CMTStr16(L"*")) && ::RemoveDirectoryW(path.Str())); } //+------------------------------------------------------------------+