MT5APIFile.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. //+------------------------------------------------------------------+
  2. //| MetaTrader 5 API |
  3. //| Copyright 2000-2019, MetaQuotes Software Corp. |
  4. //| http://www.metaquotes.net |
  5. //+------------------------------------------------------------------+
  6. #pragma once
  7. #include "MT5APIStr.h"
  8. //+------------------------------------------------------------------+
  9. //| File operations wrapper class |
  10. //+------------------------------------------------------------------+
  11. class CMTFile
  12. {
  13. public:
  14. static const UINT64 INVALID_POSITION;
  15. private:
  16. HANDLE m_file;
  17. public:
  18. CMTFile():m_file(INVALID_HANDLE_VALUE) {}
  19. virtual ~CMTFile() { Close(); }
  20. //--- file open
  21. bool Open(LPCWSTR lpFileName,const DWORD dwAccess,const DWORD dwShare,const DWORD dwCreationFlags,const DWORD dwAttributes=FILE_ATTRIBUTE_NORMAL);
  22. bool OpenRead(LPCWSTR lpFileName);
  23. bool OpenWrite(LPCWSTR lpFileName);
  24. //--- file close
  25. void Close(void);
  26. //--- file properties
  27. HANDLE Handle(void);
  28. bool IsOpen() const;
  29. UINT64 Size(void) const;
  30. static UINT64 Size(LPCWSTR path);
  31. FILETIME TimeCreate(void) const;
  32. FILETIME TimeLastAccess(void) const;
  33. FILETIME TimeLastModify(void) const;
  34. UINT64 CurrPos(void);
  35. //--- file operations
  36. DWORD Read(void *buffer,const DWORD length);
  37. DWORD Write(const void *buffer,const DWORD length);
  38. UINT64 Seek(const INT64 distance,const DWORD method);
  39. bool ChangeSize(const UINT64 size);
  40. bool Flush();
  41. //--- files group operations
  42. static int FilesCopy(const CMTStr& path,const CMTStr& newpath,const CMTStr& mask,const bool subdir);
  43. //--- directory operations
  44. static bool DirectoryCreate(const CMTStr& path);
  45. static bool DirectoryRemove(const CMTStr& path);
  46. static bool DirectoryClean(const CMTStr& path,const CMTStr& mask);
  47. };
  48. //+------------------------------------------------------------------+
  49. //| Constant declaration |
  50. //+------------------------------------------------------------------+
  51. const __declspec(selectany) UINT64 CMTFile::INVALID_POSITION=_UI64_MAX;
  52. //+------------------------------------------------------------------+
  53. //| File open |
  54. //+------------------------------------------------------------------+
  55. inline bool CMTFile::Open(LPCWSTR lpFileName,const DWORD dwAccess,const DWORD dwShare,const DWORD dwCreationFlags,const DWORD dwAttributes)
  56. {
  57. //--- close previous
  58. Close();
  59. //--- check name and open
  60. if(lpFileName)
  61. m_file=CreateFileW(lpFileName,dwAccess,dwShare,NULL,dwCreationFlags,dwAttributes,NULL);
  62. //--- return
  63. return(m_file!=INVALID_HANDLE_VALUE);
  64. }
  65. //+------------------------------------------------------------------+
  66. //| File open for read |
  67. //+------------------------------------------------------------------+
  68. inline bool CMTFile::OpenRead(LPCWSTR lpFileName)
  69. {
  70. return Open(lpFileName,GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,OPEN_EXISTING);
  71. }
  72. //+------------------------------------------------------------------+
  73. //| File open for write |
  74. //+------------------------------------------------------------------+
  75. inline bool CMTFile::OpenWrite(LPCWSTR lpFileName)
  76. {
  77. return Open(lpFileName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,CREATE_ALWAYS);
  78. }
  79. //+------------------------------------------------------------------+
  80. //| File close |
  81. //+------------------------------------------------------------------+
  82. inline void CMTFile::Close(void)
  83. {
  84. if(m_file!=INVALID_HANDLE_VALUE)
  85. {
  86. CloseHandle(m_file);
  87. m_file=INVALID_HANDLE_VALUE;
  88. }
  89. }
  90. //+------------------------------------------------------------------+
  91. //| File handle |
  92. //+------------------------------------------------------------------+
  93. inline HANDLE CMTFile::Handle(void)
  94. {
  95. return(m_file);
  96. }
  97. //+------------------------------------------------------------------+
  98. //| Check file state |
  99. //+------------------------------------------------------------------+
  100. inline bool CMTFile::IsOpen(void) const
  101. {
  102. return(m_file!=INVALID_HANDLE_VALUE);
  103. }
  104. //+------------------------------------------------------------------+
  105. //| File size |
  106. //+------------------------------------------------------------------+
  107. inline UINT64 CMTFile::Size() const
  108. {
  109. LARGE_INTEGER li={};
  110. //--- check and receive
  111. if(m_file==INVALID_HANDLE_VALUE || !::GetFileSizeEx(m_file,&li))
  112. return(0);
  113. //--- return result
  114. return((UINT64)li.QuadPart);
  115. }
  116. //+------------------------------------------------------------------+
  117. //| File size |
  118. //+------------------------------------------------------------------+
  119. inline UINT64 CMTFile::Size(LPCWSTR path)
  120. {
  121. LARGE_INTEGER li={};
  122. WIN32_FILE_ATTRIBUTE_DATA fad;
  123. //--- receive file
  124. if(GetFileAttributesExW(path,GetFileExInfoStandard,&fad))
  125. {
  126. li.LowPart =fad.nFileSizeLow;
  127. li.HighPart=(LONG)fad.nFileSizeHigh;
  128. }
  129. //--- return result
  130. return((UINT64)li.QuadPart);
  131. }
  132. //+------------------------------------------------------------------+
  133. //| File creation time |
  134. //+------------------------------------------------------------------+
  135. inline FILETIME CMTFile::TimeCreate() const
  136. {
  137. FILETIME ft={};
  138. //--- check and receive
  139. if(m_file!=INVALID_HANDLE_VALUE)
  140. GetFileTime(m_file,&ft,NULL,NULL);
  141. //--- return result
  142. return(ft);
  143. }
  144. //+------------------------------------------------------------------+
  145. //| File last access time |
  146. //+------------------------------------------------------------------+
  147. inline FILETIME CMTFile::TimeLastAccess() const
  148. {
  149. FILETIME ft={};
  150. //--- check and receive
  151. if(m_file!=INVALID_HANDLE_VALUE)
  152. GetFileTime(m_file,NULL,&ft,NULL);
  153. //--- return result
  154. return(ft);
  155. }
  156. //+------------------------------------------------------------------+
  157. //| File last modify time |
  158. //+------------------------------------------------------------------+
  159. inline FILETIME CMTFile::TimeLastModify() const
  160. {
  161. FILETIME ft={};
  162. //--- check and receive
  163. if(m_file!=INVALID_HANDLE_VALUE)
  164. GetFileTime(m_file,NULL,NULL,&ft);
  165. //--- return result
  166. return(ft);
  167. }
  168. //+------------------------------------------------------------------+
  169. //| File pointer position |
  170. //+------------------------------------------------------------------+
  171. inline UINT64 CMTFile::CurrPos()
  172. {
  173. return(CMTFile::Seek(INT64(0),FILE_CURRENT));
  174. }
  175. //+------------------------------------------------------------------+
  176. //| File read |
  177. //+------------------------------------------------------------------+
  178. inline DWORD CMTFile::Read(void *buffer,const DWORD length)
  179. {
  180. //--- check
  181. if(m_file==INVALID_HANDLE_VALUE || buffer==NULL || length<1)
  182. return(0);
  183. //--- read
  184. DWORD readed=0;
  185. if(ReadFile(m_file,buffer,length,&readed,NULL)==0)
  186. readed=0;
  187. //--- return
  188. return(readed);
  189. }
  190. //+------------------------------------------------------------------+
  191. //| Write to file |
  192. //+------------------------------------------------------------------+
  193. inline DWORD CMTFile::Write(const void *buffer,const DWORD length)
  194. {
  195. //--- check
  196. if(m_file==INVALID_HANDLE_VALUE || buffer==NULL || length<1)
  197. return(0);
  198. //--- write
  199. DWORD written=0;
  200. if(WriteFile(m_file,buffer,length,&written,NULL)==0)
  201. written=0;
  202. //--- return
  203. return(written);
  204. }
  205. //+------------------------------------------------------------------+
  206. //| Seek file pointer |
  207. //+------------------------------------------------------------------+
  208. inline UINT64 CMTFile::Seek(const INT64 distance,const DWORD method)
  209. {
  210. //--- check
  211. if(m_file==INVALID_HANDLE_VALUE)
  212. return(INVALID_POSITION);
  213. //--- fill and seek
  214. LARGE_INTEGER li={};
  215. li.QuadPart=distance;
  216. li.LowPart=SetFilePointer(m_file,(LONG)li.LowPart,&li.HighPart,method);
  217. //--- check result
  218. if(li.LowPart==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR)
  219. return(INVALID_POSITION);
  220. //--- return new file pointer position
  221. return((UINT64)li.QuadPart);
  222. }
  223. //+------------------------------------------------------------------+
  224. //| Change file size |
  225. //+------------------------------------------------------------------+
  226. inline bool CMTFile::ChangeSize(const UINT64 size)
  227. {
  228. return(CMTFile::Seek((INT64)size,FILE_BEGIN)==size && SetEndOfFile(m_file));
  229. }
  230. //+------------------------------------------------------------------+
  231. //| Flush file buffer |
  232. //+------------------------------------------------------------------+
  233. inline bool CMTFile::Flush()
  234. {
  235. if(m_file!=INVALID_HANDLE_VALUE)
  236. return(::FlushFileBuffers(m_file)!=0);
  237. return(false);
  238. }
  239. //+------------------------------------------------------------------+
  240. //| Copy files by mask |
  241. //+------------------------------------------------------------------+
  242. inline int CMTFile::FilesCopy(const CMTStr& path,const CMTStr& newpath,const CMTStr& mask,const bool subdir)
  243. {
  244. CMTStr512 src,dst,name;
  245. HANDLE hSearch;
  246. WIN32_FIND_DATAW fnd;
  247. int count=0;
  248. //--- find files
  249. src.Format(L"%s\\%s",path.Str(),mask.Str());
  250. if((hSearch=FindFirstFileW(src.Str(), &fnd))!=INVALID_HANDLE_VALUE)
  251. {
  252. do
  253. {
  254. //--- skip root directories
  255. if(CMTStr::Compare(fnd.cFileName,L".")==0 || CMTStr::Compare(fnd.cFileName,L"..")==0)
  256. continue;
  257. //--- directory?
  258. if(!(fnd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  259. {
  260. //--- create source path
  261. src.Format(L"%s\\%s",path.Str(),fnd.cFileName);
  262. //--- create dst path
  263. dst.Format(L"%s\\%s",newpath.Str(),fnd.cFileName);
  264. //--- copy file
  265. if(::CopyFileW(src.Str(),dst.Str(),FALSE)!=FALSE) count++;
  266. }
  267. else
  268. if(subdir)
  269. {
  270. //--- create path
  271. src.Format(L"%s\\%s",path.Str(),fnd.cFileName);
  272. dst.Format(L"%s\\%s",newpath.Str(),fnd.cFileName);
  273. //--- create dst path
  274. DirectoryCreate(dst);
  275. //--- copy files
  276. count+=FilesCopy(src,dst,mask,subdir);
  277. }
  278. } while(FindNextFileW(hSearch,&fnd)!=0);
  279. //--- close handle
  280. FindClose(hSearch);
  281. }
  282. //--- return copied count
  283. return(count);
  284. }
  285. //+------------------------------------------------------------------+
  286. //| Create directory with subdirectories |
  287. //+------------------------------------------------------------------+
  288. inline bool CMTFile::DirectoryCreate(const CMTStr& path)
  289. {
  290. wchar_t *cp,temp[MAX_PATH];
  291. //--- check directory
  292. if(GetFileAttributesW(path.Str())!=INVALID_FILE_ATTRIBUTES)
  293. return(true);
  294. //--- copy
  295. CMTStr::Copy(temp,path.Str());
  296. //--- parse path and create directories
  297. for(cp=temp;*cp!=L'\0';cp++)
  298. if(*cp==L'\\')
  299. {
  300. *cp=L'\0';
  301. if(GetFileAttributesW(temp)==INVALID_FILE_ATTRIBUTES)
  302. if(!::CreateDirectoryW(temp,NULL))
  303. return(false);
  304. *cp=L'\\';
  305. }
  306. //--- copy remainder
  307. if(GetFileAttributesW(temp)==INVALID_FILE_ATTRIBUTES)
  308. if(!::CreateDirectoryW(temp,NULL))
  309. return(false);
  310. //--- ok
  311. return(true);
  312. }
  313. //+------------------------------------------------------------------+
  314. //| Directory clean by mask |
  315. //+------------------------------------------------------------------+
  316. inline bool CMTFile::DirectoryClean(const CMTStr& path,const CMTStr& mask)
  317. {
  318. HANDLE hSearch;
  319. WIN32_FIND_DATAW fnd;
  320. CMTStrPath tmp;
  321. bool res=true;
  322. //--- check
  323. if(path.Empty() || path.Len()<=3)
  324. return(false);
  325. //--- create path
  326. tmp.Format(L"%s\\%s",path.Str(),mask.Str());
  327. //--- search
  328. if((hSearch=FindFirstFileW(tmp.Str(),&fnd))!=INVALID_HANDLE_VALUE)
  329. {
  330. do
  331. {
  332. //--- directory?
  333. if(fnd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  334. {
  335. //--- skip root directories
  336. if(CMTStr::Compare(fnd.cFileName,L".")==0 || CMTStr::Compare(fnd.cFileName,L"..")==0)
  337. continue;
  338. //--- create directory path
  339. tmp.Format(L"%s\\%s",path.Str(),fnd.cFileName);
  340. //--- clean directory
  341. DirectoryClean(tmp,mask);
  342. //--- delete directory
  343. res=::RemoveDirectoryW(tmp.Str()) && res;
  344. }
  345. else
  346. {
  347. //--- create file path
  348. tmp.Format(L"%s\\%s",path.Str(),fnd.cFileName);
  349. //--- delete file
  350. res=::DeleteFileW(tmp.Str()) && res;
  351. }
  352. }
  353. while(FindNextFileW(hSearch,&fnd));
  354. //--- close handle
  355. FindClose(hSearch);
  356. }
  357. //--- result
  358. return(res);
  359. }
  360. //+------------------------------------------------------------------+
  361. //| Full directory remove |
  362. //+------------------------------------------------------------------+
  363. inline bool CMTFile::DirectoryRemove(const CMTStr& path)
  364. {
  365. return(DirectoryClean(path,CMTStr16(L"*")) && ::RemoveDirectoryW(path.Str()));
  366. }
  367. //+------------------------------------------------------------------+