在 Windows 上使用 C++ 锁定文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/853805/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 12:28:01  来源:igfitidea点击:

Locking files using C++ on Windows

c++windowsfile

提问by Brian R. Bondy

I have a program writing/reading from a file, and I want to lock the file for other instances of my application. How can I do it (in c++ visual studio 2003)? I tried using the _locking() but then also I myself cannot reach the file when trying to read/write (in the same instance). I know there's an option of LockFile() but have no idea how to set it properly. Please help me.

我有一个从文件中写入/读取的程序,我想为我的应用程序的其他实例锁定该文件。我该怎么做(在 C++ Visual Studio 2003 中)?我尝试使用 _locking() 但我自己在尝试读/写时也无法访问该文件(在同一实例中)。我知道有一个 LockFile() 选项,但不知道如何正确设置它。请帮我。

回答by Brian R. Bondy

You can simply use the Win32 API CreateFileand then specify no sharing rights. This will ensure that no other processes can access the file.

您可以简单地使用 Win32 API CreateFile,然后指定不共享权限。这将确保没有其他进程可以访问该文件。

The dwShareMode DWORD specifies the type of sharing you would like, for example GENERIC_READ. If you specify 0 then that means no sharing rights should be granted.

dwShareMode DWORD 指定您想要的共享类型,例如 GENERIC_READ。如果您指定 0,则表示不应授予共享权限。

Example:

例子:

HANDLE hFile = CreateFile(_T("c:\file.txt"), GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);


If you want to only lock a certain part of the file you can use LockFileor LockFileEx.

如果您只想锁定文件的特定部分,您可以使用LockFileLockFileEx

Example:

例子:

 //Lock the first 1024 bytes
 BOOL bLocked = LockFile(hFile, 0, 0, 1024, 0);


For locking on other platforms please see my post here.

要锁定其他平台,请参阅我的帖子

回答by Shane C. Mason

You want LockFileEx() (exclusive file locking). Have a look at this discussionfrom Secure Programming Cookbook for C and C++.

您需要 LockFileEx()(独占文件锁定)。看看C 和 C++ 的安全编程手册中的这个讨论

回答by phyatt

After searching online for a while, I didn't find any good examples.

在网上搜索了一段时间,没有找到好的例子。

Here are two calls to CreateFile with the intent of locking the file for the life of a process... I use this along side the CLimitSingleInstancethat uses CreateMutex for a global named mutex.

这是对 CreateFile 的两次调用,目的是在进程的生命周期内锁定文件......我将它与CLimitSingleInstance一起使用,它使用 CreateMutex 作为全局命名互斥锁。

The first call to CreateFile attempts to open it, the second one creates it if necessary. I have a little bit more thorough implementation. I implemented it in Qt, hence the qCritical() instead of std::cout and the QDir::tempPath() instead of getting that some other way.

第一次调用 CreateFile 尝试打开它,第二次调用会在必要时创建它。我有一个更彻底的实现。我在 Qt 中实现了它,因此使用 qCritical() 而不是 std::cout 和 QDir::tempPath() 而不是通过其他方式获得。

class SingleInstance
{
protected:
    DWORD  m_dwLastError;
    HANDLE m_hFile;
public:
    SingleInstance(const char *strMutexName) {  }

    bool attemptToLockTempFile()
    {
      QString lockFile = QDir::tempPath() + "/My.exe.lock";
      m_hFile = CreateFileA(lockFile.toLocal8Bit().data(), GENERIC_READ, 0, 
                                NULL, OPEN_EXISTING, 0, NULL);
      DWORD dwLastError = GetLastError();
      if(m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
      {
          return true;
      }
      else
      {
          if(dwLastError == ERROR_FILE_NOT_FOUND )
          {
              m_hFile = CreateFileA(lockFile.toLocal8Bit().data(), GENERIC_READ, 
                                        0, NULL, CREATE_NEW, 0, NULL);
              dwLastError = GetLastError();

              if(m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
              {
                  return true;
              }
              else if(dwLastError == ERROR_SHARING_VIOLATION)
              {
                  qCritical() << "Sharing Violation on My.exe.lock";
              }
              else
              {
                  qCritical() << "Error reading" << "My.exe.lock" << "-" << dwLastError;
              }
          }
          else if(dwLastError == ERROR_SHARING_VIOLATION)
          {
              qCritical() << "Sharing Violation on My.exe.lock";
          }
          else
          {
              qCritical() << "Unable to obtain file lock -" << dwLastError;
          }
          return false;
      }
    }

    ~SingleInstance()
    {
        if ( m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
        {
            ::CloseHandle(m_hFile); //Do as late as possible.
            m_hFile = NULL;
        }
    }
}

Here is what you would have at the top of your main function:

以下是您在主函数顶部的内容:

SingleInstance g_SingleInstanceObj(globalId_QA);

// Makes sure that the program doesn't run if there is another 
// instance already running
if (g_SingleInstanceObj.IsAnotherInstanceRunning())
{
    return 0;
}