std::ofstream,在写入文件之前检查文件是否存在

38
我正在使用C++在Qt应用程序中实现文件保存功能。
我正在寻找一种在写入文件之前检查所选文件是否已经存在的方法,以便可以提示用户警告。
我正在使用std :: ofstream,而不是寻找Boost解决方案。

1
可能重复的问题:https://dev59.com/l3M_5IYBdhLWcg3waiiJ,https://dev59.com/XEbRa4cB1Zd3GeqP2aU0,https://dev59.com/0HVC5IYBdhLWcg3whRcw - Brent Writes Code
添加一个副本:https://dev59.com/XGcs5IYBdhLWcg3wh0f7 - zhangxaochen
6个回答

71

这是我最喜欢的藏在口袋里的函数之一,我经常用它来实现多种功能。

#include <sys/stat.h>
// Function: fileExists
/**
 *  Check if a file exists
 *
 * @param[in] filename - the name of the file to check
 *
 * @return    true if the file exists, else false
*/
bool fileExists(const std::string& filename)
{
    struct stat buf;
    if (stat(filename.c_str(), &buf) != -1)
    {
        return true;
    }
    return false;
}

我认为这比在没有立即使用文件进行I/O的情况下尝试打开文件更加得体。


3
使用stat而不是打开文件只为了关闭它的示例,加1。 - Chris Smith
17
+1 但是 return stat(filename.c_str(), &buf) != 1; 更加简洁。 - Matt Phillips
8
我在一台2.67GHz的Intel Xeon服务器上进行了测试。以上的stat方法用了0.93微秒来确认一个500MB的文件是否存在。下面的ifstream方法在同一文件上运行需要17.4微秒。如果要判断文件不存在,stat只需要0.72微秒,而ifstream需要2.4微秒。 - Schroeder
1
@Steve:除了Matt Phillips的代码没有声明结构体(我认为他是想让它隐含),以及他使用!= 1而不是!= -1之外,它为什么不会产生相同的效果呢? - Gurgadurgen
1
在C++中使用struct关键字有什么原因吗?除非我不知道C头文件内部存在某些名称冲突,否则这并不是必需的。 - Lightness Races in Orbit
显示剩余2条评论

42
bool fileExists(const char *fileName)
{
    ifstream infile(fileName);
    return infile.good();
}

这个方法到目前为止是最短和最具可移植性的方法。如果使用不是非常复杂,这是我会选择的方法。如果您还想提示警告,则应在主函数中执行。


8
使用ifstream构造函数尝试打开文件进行读取。当函数返回并且ifstream超出作用域时,它的析构函数将隐式关闭文件(假设文件存在且打开成功)。 - grubs
3
除了它执行了错误的操作:它检查文件是否可以被打开,而不是它是否存在。如果访问权限不允许用户访问该文件,这个函数会错误地声称该文件不存在,因为它无法打开它以进行读取。 - SasQ

10
fstream file;
file.open("my_file.txt", ios_base::out | ios_base::in);  // will not create file
if (file.is_open())
{
    cout << "Warning, file already exists, proceed?";
    if (no)
    { 
        file.close();
        // throw something
    }
}
else
{
    file.clear();
    file.open("my_file.txt", ios_base::out);  // will create if necessary
}

// do stuff with file

请注意,如果文件已经存在,这将以随机访问模式打开它。 如果您愿意,可以关闭它并以追加模式或截断模式重新打开。


1
想一想如果文件存在,但用户没有读取它的访问权限会发生什么。 - SasQ
1
@SasQ:是的...这绝对是一种hack / workaround。在C++17中,正确的解决方案是std::filesystem :: exists(),或者如果不行,使用stat() - HighCommander4
@HighCommander4,“除此之外,stat()”是什么?你想告诉我们什么? - John
1
@John 如果你的标准库实现还不支持std::filesystem,你可以使用POSIX API中的stat()函数(也支持Windows)。 - HighCommander4

6

使用C++17的std::filesystem::exists函数:

#include <filesystem> // C++17
#include <iostream>
namespace fs = std::filesystem;

int main()
{
    fs::path filePath("path/to/my/file.ext");
    std::error_code ec; // For using the noexcept overload.
    if (!fs::exists(filePath, ec) && !ec)
    {
        // Save to file, e.g. with std::ofstream file(filePath);
    }
    else
    {
        if (ec)
        {
            std::cerr << ec.message(); // Replace with your error handling.
        }
        else
        {
            std::cout << "File " << filePath << " does already exist.";
            // Handle overwrite case.
        }
    }
}

另请参阅std::error_code

如果你想检查你要写入的路径是否为普通文件,请使用std::filesystem::is_regular_file


5
尝试使用::stat()(在<sys/stat.h>中声明)

2

其中一种方法是使用stat()函数,并检查errno的值。
示例代码如下:

#include <sys/stat.h>
using namespace std;
// some lines of code...

int fileExist(const string &filePath) {
    struct stat statBuff;
    if (stat(filePath.c_str(), &statBuff) < 0) {
        if (errno == ENOENT) return -ENOENT;
    }
    else
        // do stuff with file
}

无论流的类型如何,此操作均有效。如果您仍然喜欢使用ofstream,只需使用is_open() 进行检查即可。
示例:
ofstream fp.open("<path-to-file>", ofstream::out);
if (!fp.is_open()) 
    return false;
else 
    // do stuff with file

希望这可以帮助您。谢谢!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接