Alternate e697dbe9c5997e35395fe158628dd8c5209481da
for Visual Studio 2022 and Windows 11.
読み取り中…
検索中…
一致する文字列を見つけられません
FileUtility.cpp
[詳解]
1// ----------------------------------------------------------------------------
7
8#include "pch.h"
9#include "FileUtility.h"
10#include "Event.h"
11
12using namespace alt;
13
14// ----- FileInfo
15
17{
18 _FileSize = { 0, 0 };
19}
20
22{
23
24}
25
26// ----- FileInfo1
27
29{
30 _CreateTime = { 0, 0 };
31 _UpdateTime = { 0, 0 };
32 _AccessTime = { 0, 0 };
33 _Attribute = 0;
34}
35
37{
38
39}
40
41// ----- FileInfo2
42
44{
45 _ChangeTime = { 0, 0 };
46 _FileID = 0;
47 _dwAction = (DWORD)-1;
48}
49
51{
52
53}
54
55// ----- FileUtility
56
57BOOL FileUtility::Delete (LPCTSTR name)
58{
59 return ::DeleteFile (name);
60}
61
62BOOL FileUtility::Copy (LPCTSTR source, LPCTSTR dest, BOOL bFailIfExists)
63{
64 return ::CopyFile (source, dest, bFailIfExists);
65}
66
67BOOL FileUtility::Move (LPCTSTR source, LPCTSTR dest)
68{
69 return ::MoveFile (source, dest);
70}
71
73 LPCTSTR lpctszPath, LPCTSTR lpctszPrefix, UINT nNumber)
74{
75 TString response (MAX_PATH);
76
77 ::GetTempFileName (lpctszPath, lpctszPrefix, nNumber, response.Ptr ());
78
79 return response;
80}
81
82BOOL FileUtility::MakeDir (LPCTSTR name)
83{
84 return ::CreateDirectory (name, NULL);
85}
86
87BOOL FileUtility::RemoveDir (LPCTSTR name)
88{
89 return ::RemoveDirectory (name);
90}
91
92BOOL FileUtility::SetCurrentDir (LPCTSTR name)
93{
94 return ::SetCurrentDirectory (name);
95}
96
98{
99 alt::TString response (MAX_PATH);
100
101 BOOL ret = ::GetCurrentDirectory (MAX_PATH, response.Ptr ());
102
103 return ret == TRUE ? response : NULL;
104}
105
107{
108 TString response (MAX_PATH);
109
110 GetTempPath (MAX_PATH, response.Ptr ());
111
112 return response;
113}
114
115TString FileUtility::GetAbsolutePath (LPCTSTR lpctszRelativePath)
116{
117 TString response (MAX_PATH);
118
119 ::GetFullPathName (lpctszRelativePath, MAX_PATH, response.Ptr (), NULL);
120
121 return response;
122}
123
124BOOL FileUtility::IsDirectory (LPCTSTR name)
125{
126 return ::PathIsDirectory (name);
127}
128
129BOOL FileUtility::IsExist (LPCTSTR name)
130{
131 return ::PathFileExists (name);
132}
133
134skeleton::Array<FileInfo1> FileUtility::Find (LPCTSTR target, LPCTSTR name, BOOL bRecurse)
135{
136 WIN32_FIND_DATA myFindData;
137 HANDLE hFind;
139 TString search;
140
141 search.Format (_T ("%s\\%s"), target, name);
142
143 hFind = ::FindFirstFile (search.Ctr (), &myFindData);
144 if (hFind != INVALID_HANDLE_VALUE)
145 {
146 do
147 {
148 if ((myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == NULL) ||
149 (myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == '.' && myFindData.cFileName[2] == NULL))
150 {
151 continue; // skip alias
152 }
153 else
154 {
155 FileInfo1 info;
156
157 info._FolderName = target;
158 info._FileName = myFindData.cFileName;
159 info._FileSize.HighPart = myFindData.nFileSizeHigh;
160 info._FileSize.LowPart = myFindData.nFileSizeLow;
161 info._Attribute = myFindData.dwFileAttributes;
162 info._CreateTime = myFindData.ftCreationTime;
163 info._UpdateTime = myFindData.ftLastWriteTime;
164 info._AccessTime = myFindData.ftLastAccessTime;
165
166 response.Add (info);
167 }
168 } while (::FindNextFile (hFind, &myFindData));
169
170 // 本当なら、ここでGetLastError()がERROR_NO_MORE_DATAであることを確認したほうがいい。
171
172 ::FindClose (hFind);
173 }
174
175 if (bRecurse)
176 {
177 search.Format (_T ("%s\\%s"), target, _T ("\\*"));
178 hFind = ::FindFirstFile (search.Ctr (), &myFindData);
179 if (hFind != INVALID_HANDLE_VALUE)
180 {
181 do
182 {
183 if ((myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == NULL) ||
184 (myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == '.' && myFindData.cFileName[2] == NULL))
185 {
186 continue; // skip alias
187 }
188 else if (myFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
189 {
190 search.Format (_T ("%s\\%s"), target, myFindData.cFileName);
191 // 以下のやり方では、失敗する。
192 // response += Find (search.Ctr (), name, bRecurse);
193 // 一度tempに受けてから+=を行うと安定する。原因不明......
194 skeleton::Array<FileInfo1> temp = Find (search.Ctr (), name, bRecurse);
195 response += temp;
196 }
197
198 } while (::FindNextFile (hFind, &myFindData));
199 }
200 }
201
202 return response;
203}
204
205VOID FileUtility::Find2 (LPCTSTR target, LPCTSTR name, BOOL bRecurse, skeleton::Array<FileInfo1>& response)
206{
207 WIN32_FIND_DATA myFindData;
208 HANDLE hFind;
209 TString search;
210
211 search.Format (_T ("%s\\%s"), target, name);
212
213 hFind = ::FindFirstFile (search.Ctr (), &myFindData);
214 if (hFind != INVALID_HANDLE_VALUE)
215 {
216 do
217 {
218 if ((myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == NULL) ||
219 (myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == '.' && myFindData.cFileName[2] == NULL))
220 {
221 continue; // skip alias
222 }
223 else
224 {
225 FileInfo1 info;
226
227 info._FolderName = target;
228 info._FileName = myFindData.cFileName;
229 info._FileSize.HighPart = myFindData.nFileSizeHigh;
230 info._FileSize.LowPart = myFindData.nFileSizeLow;
231 info._Attribute = myFindData.dwFileAttributes;
232 info._CreateTime = myFindData.ftCreationTime;
233 info._UpdateTime = myFindData.ftLastWriteTime;
234 info._AccessTime = myFindData.ftLastAccessTime;
235
236 response.Add (info);
237 }
238 } while (::FindNextFile (hFind, &myFindData));
239
240 // 本当なら、ここでGetLastError()がERROR_NO_MORE_DATAであることを確認したほうがいい。
241
242 ::FindClose (hFind);
243 }
244
245 if (bRecurse)
246 {
247 search.Format (_T ("%s\\%s"), target, _T ("\\*"));
248 hFind = ::FindFirstFile (search.Ctr (), &myFindData);
249 if (hFind != INVALID_HANDLE_VALUE)
250 {
251 do
252 {
253 if ((myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == NULL) ||
254 (myFindData.cFileName[0] == '.' && myFindData.cFileName[1] == '.' && myFindData.cFileName[2] == NULL))
255 {
256 continue; // skip alias
257 }
258 else if (myFindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
259 {
260 search.Format (_T ("%s\\%s"), target, myFindData.cFileName);
261 Find2 (search.Ctr (), name, bRecurse, response);
262 }
263
264 } while (::FindNextFile (hFind, &myFindData));
265 }
266 }
267
268 return;
269}
270
271skeleton::Array<FileInfo2> FileUtility::DirectoryWatch (LPCTSTR lpctszWatchDirectory, DWORD dwTimeout)
272{
273 BOOL ret = FALSE;
275 HANDLE hDirectory;
276 Event notifyEvent;
277 DWORD dwResponse;
278 DWORD dwNotifyFilter;
279 BOOL bContinue = FALSE;
280
281 dwNotifyFilter =
282 FILE_NOTIFY_CHANGE_FILE_NAME |
283 FILE_NOTIFY_CHANGE_DIR_NAME |
284 FILE_NOTIFY_CHANGE_ATTRIBUTES |
285 FILE_NOTIFY_CHANGE_SIZE |
286 FILE_NOTIFY_CHANGE_LAST_WRITE |
287 FILE_NOTIFY_CHANGE_LAST_ACCESS |
288 FILE_NOTIFY_CHANGE_CREATION;
289
290 do
291 {
292 hDirectory =
293 ::CreateFile (
294 lpctszWatchDirectory,
295 FILE_LIST_DIRECTORY,
296 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
297 NULL,
298 OPEN_EXISTING,
299 FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
300 NULL);
301
302 if (hDirectory == INVALID_HANDLE_VALUE)
303 {
304 break;
305 }
306
307 ret = notifyEvent.Create (NULL, FALSE, FALSE);
308 if (ret == FALSE)
309 {
310 break;
311 }
312
313 bContinue = TRUE;
314
315 } while (false);
316
317 while (bContinue)
318 {
319 OVERLAPPED stOverlapped;
320 ZeroMemory (&stOverlapped, sizeof (stOverlapped));
321 stOverlapped.hEvent = notifyEvent.GetHandle ();
322
323 CONST DWORD cdwBufferLength = 4096;
324 WCHAR* buffer = new WCHAR[cdwBufferLength];
325 ZeroMemory (buffer, sizeof (WCHAR) * cdwBufferLength);
326
327 BOOL bWatchSubtree = TRUE;
328
329 ret = ::ReadDirectoryChangesExW (
330 hDirectory,
331 buffer,
332 sizeof (WCHAR) * cdwBufferLength,
333 bWatchSubtree,
334 dwNotifyFilter,
335 &dwResponse,
336 &stOverlapped,
337 NULL,
338 READ_DIRECTORY_NOTIFY_INFORMATION_CLASS::ReadDirectoryNotifyExtendedInformation);
339 if (ret == FALSE)
340 {
341 bContinue = FALSE;
342 break;
343 }
344
345 DWORD dwEvent = notifyEvent.Wait (dwTimeout);
346 if (dwEvent != WAIT_OBJECT_0)
347 {
348 bContinue = FALSE;
349 break;
350 }
351 else
352 {
353 ret = TRUE;
354 }
355
356 PFILE_NOTIFY_EXTENDED_INFORMATION currentPFNI = (PFILE_NOTIFY_EXTENDED_INFORMATION)buffer;
357
358 for (INT i = 0; ;)
359 {
360 if (currentPFNI->Action > 5)
361 {
362 FileInfo2 errorInfo;
363 errorInfo._dwAction = (DWORD)-1;
364 response.Add (errorInfo);
365 bContinue = FALSE;
366 break;
367 }
368
369 if (currentPFNI->Action > 0)
370 {
371 TString fileName (MAX_PATH);
372 FileInfo2 info2;
373
374 CopyMemory (fileName.Ptr (), currentPFNI->FileName, currentPFNI->FileNameLength);
375 info2._dwAction = currentPFNI->Action;
376 info2._FileName = fileName;
377 info2._FileSize.QuadPart = currentPFNI->FileSize.QuadPart;
378 // GetSystemTime()ベースの時刻になります。
379 info2._CreateTime.dwLowDateTime = currentPFNI->CreationTime.LowPart;
380 info2._CreateTime.dwHighDateTime = currentPFNI->CreationTime.HighPart;
381 info2._UpdateTime.dwLowDateTime = currentPFNI->LastModificationTime.LowPart;
382 info2._UpdateTime.dwHighDateTime = currentPFNI->LastModificationTime.HighPart;
383 info2._AccessTime.dwLowDateTime = currentPFNI->LastAccessTime.LowPart;
384 info2._AccessTime.dwHighDateTime = currentPFNI->LastAccessTime.HighPart;
385 info2._ChangeTime.dwLowDateTime = currentPFNI->LastChangeTime.LowPart;
386 info2._ChangeTime.dwHighDateTime = currentPFNI->LastChangeTime.HighPart;
387 info2._Attribute = currentPFNI->FileAttributes;
388 info2._FileID = currentPFNI->FileId.QuadPart;
389
390 response.Add (info2);
391 }
392
393 currentPFNI += currentPFNI->NextEntryOffset;
394 if (currentPFNI->NextEntryOffset == 0) break;
395 i += currentPFNI->NextEntryOffset;
396 }
397
398 delete[] buffer;
399 }
400
401 CloseHandle (hDirectory);
402 return response;
403}
404
405#if defined (_MSC_VER) && (_MSC_VER >= 1910) // VS2017 over
406
407BOOL FileUtility::MakeSymbolicLink (LPCTSTR source, LPCTSTR link, BOOL isFile)
408{
409 DWORD dwFlags = isFile == TRUE ? 0 : SYMBOLIC_LINK_FLAG_DIRECTORY;
410
411 dwFlags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
412
413 return ::CreateSymbolicLink (link, source, dwFlags);
414}
415
416#endif
417
418BOOL FileUtility::MakeHardLink (LPCTSTR source, LPCTSTR link)
419{
420 return ::CreateHardLink (link, source, NULL);
421}
422
424 ShellOperation operation, LPCTSTR lpctszFrom, LPCTSTR lpctszTo)
425{
426 INT response;
427 SHFILEOPSTRUCT shellOperation{ NULL, NULL, NULL, NULL, NULL };
428 TCHAR tszzFrom[MAX_PATH]{ NULL };
429 TCHAR tszzTo[MAX_PATH]{ NULL };
430
431 wsprintf (tszzFrom, _T ("%s\0"), lpctszFrom);
432 wsprintf (tszzTo, _T ("%s\0"), lpctszTo);
433
434 shellOperation.hwnd = NULL;
435 shellOperation.wFunc = (WORD)operation;
436 shellOperation.pFrom = tszzFrom;
437 shellOperation.pTo = tszzTo;
438 shellOperation.fFlags = FOF_NO_UI;
439
440 response = ::SHFileOperation (&shellOperation);
441 ::SHChangeNotify (SHCNE_UPDATEDIR, SHCNF_PATH, (LPCVOID)tszzTo, 0);
442
443 return response;
444}
イベントに関するWindowsAPIを集約したクラス
ファイルハンドルを伴わないファイルIOに関するWindowsAPIを集約した クラス
プリコンパイル済みヘッダー ファイルです。
イベントに関するWindowsAPIを集約したクラス
Definition: Event.h:16
BOOL APIENTRY Create(LPCTSTR lpctszName, BOOL bManualReset, BOOL bInitialState)
イベントを作成します。
Definition: Event.cpp:12
FileUtility::Find()が返すファイル情報
Definition: FileUtility.h:60
FILETIME _AccessTime
Definition: FileUtility.h:146
FILETIME _CreateTime
Definition: FileUtility.h:144
APIENTRY ~FileInfo1()
デストラクタ
Definition: FileUtility.cpp:36
APIENTRY FileInfo1()
コンストラクタ
Definition: FileUtility.cpp:28
FILETIME _UpdateTime
Definition: FileUtility.h:145
APIENTRY FileInfo2()
コンストラクタ
Definition: FileUtility.cpp:43
FILETIME _ChangeTime
Definition: FileUtility.h:221
LONGLONG _FileID
Definition: FileUtility.h:222
APIENTRY ~FileInfo2()
デストラクタ
Definition: FileUtility.cpp:50
ULARGE_INTEGER _FileSize
Definition: FileUtility.h:55
TString _FileName
Definition: FileUtility.h:54
APIENTRY FileInfo()
コンストラクタ
Definition: FileUtility.cpp:16
virtual APIENTRY ~FileInfo()
デストラクタ
Definition: FileUtility.cpp:21
TString _FolderName
Definition: FileUtility.h:53
static skeleton::Array< FileInfo1 > APIENTRY Find(LPCTSTR target, LPCTSTR name, BOOL bRecurse=FALSE)
ファイルの検索
static TString APIENTRY GetTemporaryFileName(LPCTSTR lpctszPath, LPCTSTR lpctszPrefix, UINT nNumber)
テンポラリファイル名を取得します。
Definition: FileUtility.cpp:72
static BOOL APIENTRY RemoveDir(LPCTSTR name)
ディレクトリの削除
Definition: FileUtility.cpp:87
static TString APIENTRY GetCurrentDir()
カレントディレクトリ名の取得
Definition: FileUtility.cpp:97
static VOID APIENTRY Find2(LPCTSTR target, LPCTSTR name, BOOL bRecurse, skeleton::Array< FileInfo1 > &response)
static BOOL APIENTRY Move(LPCTSTR source, LPCTSTR dest)
ファイルの移動
Definition: FileUtility.cpp:67
static INT APIENTRY SHFileOperations(ShellOperation operation, LPCTSTR lpctszFrom, LPCTSTR lpctszTo)
static BOOL APIENTRY SetCurrentDir(LPCTSTR name)
カレントディレクトリの移動
Definition: FileUtility.cpp:92
static BOOL APIENTRY MakeHardLink(LPCTSTR source, LPCTSTR link)
ハードリンクの作成
static BOOL APIENTRY IsDirectory(LPCTSTR name)
ディレクトリの存在確認
static BOOL APIENTRY MakeDir(LPCTSTR name)
ディレクトリの作成
Definition: FileUtility.cpp:82
static TString APIENTRY GetAbsolutePath(LPCTSTR lpctszRelativePath)
カレントディレクトリのパスを連結して絶対パスの作成
static BOOL APIENTRY Copy(LPCTSTR source, LPCTSTR dest, BOOL bFailIfExists=FALSE)
ファイルのコピー
Definition: FileUtility.cpp:62
static skeleton::Array< FileInfo2 > APIENTRY DirectoryWatch(LPCTSTR lpctszWatchDirectory, DWORD dwTimeout)
ディレクトリの監視
static BOOL APIENTRY IsExist(LPCTSTR name)
ディレクトリ・ファイルの存在確認
static BOOL APIENTRY Delete(LPCTSTR name)
ファイルの削除
Definition: FileUtility.cpp:57
static TString APIENTRY GetTemporaryPath()
テンポラリフォルダを取得します。
HANDLE APIENTRY GetHandle() const
継承先はこの関数でハンドルを取得します。
文字列に関するWindowsAPIを集約したクラス
Definition: TString.h:17
TString &APIENTRY Format(LPCTSTR format,...)
フォーマットに従ってパラメータを文字列化します。
Definition: TString.cpp:333
LPCTSTR APIENTRY Ctr() const
内部で確保している文字列ポインタを取得します。
Definition: TString.h:46
LPTSTR APIENTRY Ptr() const
内部で確保している文字列ポインタを取得します。
Definition: TString.h:42
DWORD APIENTRY Wait(DWORD dwWaitTime=INFINITE) const
シグナル状態になるとブロックを解除します。
サイズ可変の配列を具現したクラス
Definition: Array.hpp:20
VOID APIENTRY Add(T &item)
Array<T>へ値を追加
Definition: Array.hpp:83
Definition: DBLibrary.h:12
ShellOperation
SHFILEOPSTRUCT.wFuncに渡す、値の列挙
Definition: FileUtility.h:21