How do I monitor the file lock to see when it is released? [C ++]
I am looking for a way to create a program in unmanaged C ++ that waits until the file is unlocked (as it is no longer used in it), but something. I had no luck finding how to do this, any help would be appreciated!
UPDATE: I may have answered my own question, take a look below and tell you what you think.
UPDATE: all that really matters is the file is writable, it doesn't matter if it's still in use.
a source to share
Here is one possible solution to my problem: does anyone see a problem with this?
#include <iostream>
#include <fstream>
#include <windows.h>
using namespace std;
void main(int argc, char ** argv) {
if (argc < 2 || argc > 2) {
return;
}
ofstream myfile;
myfile.open(argv[1], ios_base::app);
while (!myfile.is_open()) { Sleep(100); myfile.open(argv[1], ios_base::app); }
myfile.close();
// file should now be unlocked..
}
Thanks again!
UPDATE: changed the code to be more complete.
a source to share
Something like this will wait without wasting CPU cycles.
HANDLE h = FindFirstChangeNotification("C:\Path to folder holding file", FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
while(true)
{
if (CheckLockFile("C:\Path to file"))
{
// Do something
break;
}
WaitForSingleObject(h, APPROPRIATE_TIMEOUT_VALUE);
FindNextChangeNotification(h);
}
bool CheckLockFile(char* FilePath)
{
HANDLE fh = CreateFile(FilePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0,NULL);
if (fh == INVALID_HANDLE_VALUE)
{
return false;
}
CloseHandle(fh);
return true;
}
This assumes that the file-locked application has it open for writing.
a source to share
Create a loop that calls :: CreateFile () every 5 seconds until it succeeds. Pass 0 in the dwShareMode argument to make sure there is no other process that has the file open.
a source to share
It looks like you want to access the file after another program has released the lock. UNIX (and Cygwin) gives you this behavior by simply locking the file.
By using something like ScopeGuard
you can make it File_locker
unnecessary, but if you are not using ScopeGuard
, follow these steps:
UNIX:
#include <stdexcept>
#include <string>
#include "sys/file.h" //flock
#include "sys/fcntl.h" //open
class File_locker {
int file_descriptor;
public:
File_locker(std::string filename)
{
// you can use errno to determine why the open/flock failed,
// but this is a demo, not production code
file_descriptor = ::open(filename.c_str(), O_RDWR);
if (file_descriptor < 0)
throw std::runtime_error((std::string("unable to open file ")
+ filename).c_str());
if (::flock(file_descriptor, LOCK_EX)) {
::close(file_descriptor);
throw std::runtime_error((std::string("unable to flock file ")
+ filename).c_str());
}
}
~File_locker()
{
::flock(file_descriptor, LOCK_UN); // don't forget to unlock
::close(file_descriptor);
}
};
On Windows, it seems like you should poll the file.
Window:
#include <string>
#include "windows.h"
class File_locker {
HANDLE file_handle;
static const int MAX_TRIES = 10;
static const int SLEEP_INTERVAL = 500;
public:
File_locker(std::string filename)
{
// you can use GetLastError() to determine why the open failed,
// but this is a demo, not production code
for (int i = 0; i < MAX_TRIES; ++i) {
file_handle = ::CreateFile(filename.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (file_handle != INVALID_HANDLE_VALUE)
return;
::Sleep(SLEEP_INTERVAL);
}
throw std::runtime_error((std::string("unable to open file ")
+ filename).c_str());
}
~File_locker()
{
::CloseHandle(file_handle);
}
};
Use it like this:
#include <fstream>
#include <stdexcept>
// .. define File_locker, as above
int main()
{
try {
File_locker fl("filename.txt");
// once fl is constructed, nobody else has the file locked
std::fstream file("filename.txt");
// ...
return 0;
}
catch (std::runtime_error& ex)
{
// just bail
return 1;
}
}
a source to share