简体   繁体   中英

C++ How do I make it so my program wouldn't delete files that are in use?

So basically, I'm listing all of the files in my temp directory, and then deleting them. Obviously, some of the files are in use and the program itself is using the files that it's deleting. I tried fiddling around with SHFileOperation with no success. (tbh I got no idea how to use it). How do I make it check if the file is in use by another program before deleting it? Thanks!

This is giving me the error: fs::remove_all(entry.path());

Code:

#include <iostream>
#include <Windows.h>
#include <filesystem>
#include <lmcons.h>
#include <fileapi.h>
#include "cColors.h"
using namespace std;

namespace fs = filesystem;
char type;

int main()
{
    SetConsoleTextAttribute(h, 15);

    while (true)
    {
        cout << "[~] Are you sure you want to run Windows Cleaner? [Y/N]";
        cin >> type;

        if (type == 'n')
        {
            break;
            exit(0);
        }
        else if (type == 'y')
        {
            cout << "[#] Cleaning temp directory\n";

            for (const auto& entry : fs::directory_iterator(fs::temp_directory_path()))
            {
                cout << "[#] Deleting " << entry.path();
                fs::remove_all(entry.path()); //This is giving me the error
            }       
        }
        else
        {
            break;
            exit(0);
        }
    }
}

Catch the exception Just ignore the error and continue. Or use the second form and pass an error_code argument. Than you get no exception and you can check the reason why it failed.

If the file is in use you get an error. So you can't delete it. If you have no rights you can't delete it too.

Checking the usage first is a race condition. After the check, the file might get closed and you may be able to delete it safely. There is no difference in checking first and than delete it or trying to delete it and it fails.

Here's what I came up with. A recursive delete function which uses CreateFile . My original comment

Maybe you could use CreateFile with desired access 0 and share mode OPEN_EXISTING. Then you have to check the failing reason. If it doesn't fail; close and delete.

wasn't 100% correct. dwDesiredAccess should be 0 , dwShareMode should be FILE_SHARE_DELETE , dwCreationDisposition should be OPEN_EXISTING and dwFlagsAndAttributes should be FILE_FLAG_DELETE_ON_CLOSE . If then a valid handle is received the last CloseHandle on the file will lead to deletion (see here ).

Here's an example:

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <tchar.h>
#include <iostream>
#include <filesystem>

#ifdef _UNICODE
auto& cout = std::wcout;
#else
using std::cout;
#endif // _UNICODE
using std::endl;
namespace fs=std::filesystem;

void deleteRecursive(const fs::path& path);
void tryDeleteFile(const fs::path& path);

int main(int argc, char* argv[])
{
    TCHAR tempDir[255];
    GetEnvironmentVariable(_T("TEMP"), tempDir, 255);
    deleteRecursive(fs::path(tempDir));
    return 0;
}

void deleteRecursive(const fs::path& path)
{
    fs::directory_iterator dirs(path);
    for (const auto& entry : dirs)
    {
        const auto& path = entry.path();
        if (entry.is_directory())
        {
            deleteRecursive(path);
            if (fs::is_empty(path))
            {
                if (!RemoveDirectory(path.c_str()))
                {
                    cout << _T("Can't delete dir: ") << path << endl;
                }
            }
        }
        else
        {
            tryDeleteFile(path);
        }
    }
}

void tryDeleteFile(const fs::path& path)
{
    const auto file = path.c_str();
    HANDLE fileHandle = CreateFile(
        file,                      // lpFileName,
        0,                         // dwDesiredAccess,
        FILE_SHARE_DELETE,         // dwShareMode,
        NULL,                      // lpSecurityAttributes,
        OPEN_EXISTING,             // dwCreationDisposition,
        FILE_FLAG_DELETE_ON_CLOSE, // dwFlagsAndAttributes,
        NULL                       // hTemplateFile
    );
    if (fileHandle == INVALID_HANDLE_VALUE)
    {
        DWORD lastErr = GetLastError();
        if (lastErr != ERROR_FILE_NOT_FOUND) // gone in the mean time
        {
            cout << _T("Can't delete file: ") << file << endl;
        }
    }
    else
    {
        CloseHandle(fileHandle);
    }
}

tryDeleteFile contains the crucial part.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM