CreateFile 失败,错误代码为 2,而文件存在

Posted

技术标签:

【中文标题】CreateFile 失败,错误代码为 2,而文件存在【英文标题】:CreateFile failing with errorcode 2, while file exists 【发布时间】:2015-11-10 10:01:52 【问题描述】:

我尝试通过 CreateFile 打开现有文件,但它总是以 errorcode 2 失败 - 就像文件不存在,但它存在 - 它在可执行文件的文件夹中。

hFile = CreateFile( argv[ 1 ], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
if ( hFile == INVALID_HANDLE_VALUE )

    printf( "\nError: Unable to open file (%d)\n", GetLastError( ) );
    return -1;

即使我用硬编码的文件名字符串替换argv[1],它也会失败。 应用程序正在以管理员身份运行。

【问题讨论】:

如果你从 IDE 运行它(我假设是 Visual Studio),afaik 你必须将文件放到包含源代码的文件夹中(默认文件夹) 我找到了解决方案 - 如果文件名是 file.txt CreateFile 不想要 file.txt 输入但 C:\\file.txt 使用相对路径并不是一个错误。 在the 文档中没有说,该函数需要绝对路径。您是否尝试检查当前目录? @IInspectable 我想你很清楚我知道我在 Windows 上的方式。我知道ls 不是 Windows 的一部分。它是一个 GNU 工具,可以在 Windows 上完美运行。我知道我知道。无论这个特定工具是否以这种方式实现它,对简单的 CLI 程序使用相对路径都是一个有效的选择。碰巧的是,我现在正在查看的ls 不会导入GetCurrentDirectory。 FWIW。 【参考方案1】:

错误代码是准确的。找不到该文件。可能的解释包括:

您使用了错误的文件名。 您使用了相对路径,并且进程工作目录不是您所期望的。

如果您希望将文件名解释为相对于可执行文件所在的目录,请执行此操作。从包含可执行文件和指定文件名的目录形成绝对路径。

没有理由期望进程工作目录是可执行文件所在的目录。

【讨论】:

【参考方案2】:

您正在尝试使用相对路径名打开文件。相对路径名是相对于当前工作目录的(参见GetCurrentDirectory)。当前工作目录不一定是可执行映像所在的目录。它可能因多种原因而不同,例如:

应用程序是通过明确设置工作目录的快捷方式启动的。 应用程序名为SetCurrentDirectory。 应用程序是通过命令解释器从可执行文件目录以外的目录启动的。

如果要打开相对于应用程序的可执行映像的文件,则需要根据可执行文件的位置和所需的文件名构造一个完全限定的路径名​​。以下代码检索可执行文件的目录1)

#include <windows.h>
#include <Shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <string>
#include <vector>

std::wstring GetExePath() 
    // Retrieve fully qualified module pathname
    std::vector<wchar_t> buffer( MAX_PATH );
    DWORD cbSize = ::GetModuleFileNameW( nullptr, buffer.data(),
                                         static_cast<DWORD>( buffer.size() ) );
    while ( cbSize == buffer.size() ) 
        buffer.resize( buffer.size() + MAX_PATH );
        cbSize = ::GetModuleFileNameW( nullptr, buffer.data(),
                                       static_cast<DWORD>( buffer.size() ) );
    
    if ( cbSize == 0 ) 
        throw ::GetLastError();
    

    // Remove filename from fully qualified pathname
    if ( ::PathRemoveFileSpecW( buffer.data() ) ) 
        ::PathAddBackslashW( buffer.data() );
    

    // Construct string object from character buffer
    std::wstring str( &buffer[0] );
    return str;

可以这样使用:

int wmain( int argc, const wchar_t* argv[] ) 

    if ( argc <= 1 ) 
        return -1;
    

    std::wstring pathname = GetExePath();
    pathname += argv[1];
    HANDLE hFile = ::CreateFileW( pathname.c_str(), GENERIC_READ,
                                  FILE_SHARE_READ | FILE_SHARE_WRITE,
                                  NULL, OPEN_EXISTING, 0, NULL );
    if ( hFile == INVALID_HANDLE_VALUE )
    
        wprintf( L"\nError: Unable to open file (%d)\n", GetLastError() );
        return -1;
    

    // ...

    ::CloseHandle( hFile );
    return 0;


1) 面向 Windows 8 及更高版本的代码应改用 PathCchRemoveFileSpec 和 PathCchAddBackslash。

【讨论】:

+1。还有一个可能的原因:应用程序是使用“以管理员身份运行”启动的,或者被配置为需要提升。 (当前目录始终是system32 文件夹。)

以上是关于CreateFile 失败,错误代码为 2,而文件存在的主要内容,如果未能解决你的问题,请参考以下文章

两个线程一个使用流 Api,另一个线程 CreateFile 失败并出现错误 ERROR_SHARING_VIOLATION

CreateFile() 在 Windows XP 中工作,但在 Windows 7 中失败,返回句柄无效

detours hooked CreateFile 函数触发堆栈溢出

无法并行读取相同的文件

根据 GetLastError 直接写磁盘导致错误代码 5

CreateFile 返回错误 INVALID_HANDLE_VALUE(对于 COM 端口),GetLastError 返回“找不到指定的文件”