【问题标题】:Fake files "exist" after checking real files?检查真实文件后假文件“存在”?
【发布时间】:2017-12-27 07:08:29
【问题描述】:

我在 Linux 上编程 C++ 已经有一段时间了,但最近转到了 Windows 10 计算机。

我设法用 w64-mingw 设置了 CodeBlocks。

我一直在尝试将程序从 linux 移动到 windows,但我遇到了文件名问题。例如,我有代码来检查文件或目录是否存在,并创建目录。但是我得到了奇怪的结果,如果文件检查返回为真,那么所有后续文件检查都返回为真。我有示例代码,其中 test.txt 和 testdir 是最初不存在但由程序创建的文件和目录。 fail.txt 和 faildir 永远不存在,但我的程序声称它们在创建 test.txt 和 testdir 之后就存在。我见过几个关于检查 Windows 上是否存在文件的问题,但我从来没有遇到过这样的行为,而且我不确定发生了什么。调用 GetFileAttributes() 时,Windows 是否无法重新初始化某些内容?还是我错过了一些非常基本的东西?

ma​​in.cpp

#include <iostream>
#include <fstream>
#include "../include/FileChecker.h"

int main(){
    FileChecker fc = FileChecker();
    std::cout << "Test Start" << std::endl;

    #ifdef _WIN32
    std::cout << "OS is windows" << std::endl;
    #endif // _WIN32
    std::cout << std::endl;
    std::cout << "Nothing should exist" << std::endl;

    if(fc.file_exists("test.txt")){
        std::cout << "test.txt exists." << std::endl;
    }else{
        std::cout << "test.txt does not exist." << std::endl;
    }
    if(fc.file_exists("fail.txt")){
        std::cout << "fail.txt exists." << std::endl;
    }else{
        std::cout << "fail.txt does not exist." << std::endl;
    }

    if(fc.directory_exists("testdir")){
        std::cout << "Directory testdir exists." << std::endl;
    }else{
        std::cout << "Directory testdir does not exist." << std::endl;
    }
    if(fc.directory_exists("faildir")){
        std::cout << "Directory faildir exists." << std::endl;
    }else{
        std::cout << "Directory faildir does not exist." << std::endl;
    }
    std::cout << std::endl;
    std::cout << "Creating test.txt" << std::endl;
    std::ofstream test("test.txt");
    test << "HELLO" << std::endl;
    test.close();

    std::cout << "Only test.txt should exist" << std::endl;
    if(fc.file_exists("test.txt")){
        std::cout << "test.txt exists." << std::endl;
    }else{
        std::cout << "test.txt does not exist." << std::endl;
    }
    if(fc.file_exists("fail.txt")){
        std::cout << "fail.txt exists." << std::endl;
    }else{
        std::cout << "fail.txt does not exist." << std::endl;
    }
    if(fc.directory_exists("testdir")){
        std::cout << "Directory testdir exists." << std::endl;
    }else{
        std::cout << "Directory testdir does not exist." << std::endl;
    }
    if(fc.directory_exists("faildir")){
        std::cout << "Directory faildir exists." << std::endl;
    }else{
        std::cout << "Directory faildir does not exist." << std::endl;
    }
    std::cout << std::endl;
    std::cout << "Creating directory testdir" << std::endl;
    if(fc.create_directory("testdir")){
        std::cout << "Creation Success" << std::endl;
    }else{
        std::cout << "Creation Failed" << std::endl;
    }

    std::cout << "Only testdir should exist" << std::endl;
        if(fc.directory_exists("testdir")){
        std::cout << "Directory testdir exists." << std::endl;
    }else{
        std::cout << "Directory testdir does not exist." << std::endl;
    }
    if(fc.directory_exists("faildir")){
        std::cout << "Directory faildir exists." << std::endl;
    }else{
        std::cout << "Directory faildir does not exist." << std::endl;
    }

    return 0;
}

FileChecker.h

    #ifndef FILECHECKER_H
    #define FILECHECKER_H


    #ifdef _WIN32
    #include <windows.h>
    #include <tchar.h>
    #include <stdio.h>
    #include <direct.h>
    #endif // _WIN32

    #include <string>


    class FileChecker
    {
        public:

            FileChecker();
            virtual ~FileChecker();

            bool file_exists(std::string filename);
            bool directory_exists(std::string dirname);
            bool create_file(std::string filename);
            bool create_directory(std::string dirname);

        protected:

        private:
    };

    #endif // FILECHECKER_H

FileChecker.cpp

#include "../include/FileChecker.h"

FileChecker::FileChecker(){
    //ctor

}


FileChecker::~FileChecker(){
    //dtor

}



#ifdef _WIN32
bool FileChecker::file_exists(std::string filename){
    static LPCTSTR szPath = TEXT(filename.c_str());
    DWORD dwAttrib = GetFileAttributes(szPath);
    return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
#endif // _WIN32


#ifdef _WIN32
bool FileChecker::directory_exists(std::string dirname){
    static LPCTSTR szPath = TEXT(dirname.c_str());
    DWORD dwAttrib = GetFileAttributes(szPath);
    return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
#endif // _WIN32


#ifdef _WIN32
bool FileChecker::create_directory(std::string dirname){
    static LPCTSTR szPath = TEXT(dirname.c_str());
    return(CreateDirectory(szPath, NULL));
}
#endif // _WIN32

输出

【问题讨论】:

    标签: c++ windows filepath


    【解决方案1】:

    您应该删除函数中的所有 static 关键字。

    bool FileChecker::file_exists(std::string filename){
    static LPCTSTR szPath = TEXT(filename.c_str());  // <--- [*]
    DWORD dwAttrib = GetFileAttributes(szPath);
    

    file_exists函数第一次被调用时,szPath变量被创建并初始化指向filename的字符数组。第二次调用file_exists时,szPath的值还是一样,指向无效数据(保持指向文件名对象数据的指针,第一次调用file_exists后被删除)。

    您应该了解函数中的静态变量。

    【讨论】:

    • 这似乎已经解决了。我从其他 stackexchange 答案中得到了“静态 LPCTSTR ...”,但他们从未解释过为什么会出现,所以我一定认为出于某种原因这是必要的。谢谢。
    【解决方案2】:

    你的代码在这里:

    bool FileChecker::file_exists(std::string filename){    
        static LPCTSTR szPath = TEXT(filename.c_str());
        DWORD dwAttrib = GetFileAttributes(szPath);
        return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
    }
    

    TEXT 只是强制转换,它不执行任何类型的转换。改为:

    bool FileChecker::file_exists(std::string filename)
    {
        DWORD dwAttrib = GetFileAttributesA(filename.c_str());
        return ((dwAttrib != INVALID_FILE_ATTRIBUTES) && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
    }
    

    【讨论】:

    • 如果我们使用 unicode 字符串,跳过强制转换会导致问题吗?
    猜你喜欢
    • 1970-01-01
    • 2013-01-11
    • 2015-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多