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

Posted

技术标签:

【中文标题】std::ofstream,写入前检查文件是不是存在【英文标题】:std::ofstream, check if file exists before writingstd::ofstream,写入前检查文件是否存在 【发布时间】:2011-05-18 00:24:22 【问题描述】:

我正在使用 C++ 在 Qt 应用程序中实现文件保存功能。

我正在寻找一种在写入之前检查所选文件是否已经存在的方法,以便向用户提示警告。

我正在使用std::ofstream,我不是在寻找 Boost 解决方案。

【问题讨论】:

可能重复的问题:***.com/questions/1383617/…、***.com/questions/574285/…、***.com/questions/268023/… 添加副本:***.com/questions/12774207/… 【参考方案1】:

试试::stat()(在<sys/stat.h>中声明)

【讨论】:

【参考方案2】:

这是我最喜欢的隐藏功能之一,我经常使用它。

#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 的意图,我发现这比尝试打开文件更有品味。

【讨论】:

+1 示例使用 stat 而不是打开文件只是为了关闭它。 +1 但return stat(filename.c_str(), &amp;buf) != 1; 更紧凑。 我在 2.67GHz Intel Xeon 上计时。上面的 stat 方法花了 0.93 微秒来确认一个 500MB 的文件存在。下面的 ifstream 方法在同一个文件上花费了 17.4 微秒。要判断文件不存在,stat 用了 0.72 微秒,ifstream 用了 2.4 微秒。 @Steve:除了 Matt Phillips 的代码没有声明结构(我认为他的意思是暗示)以及他使用 != 1 而不是 @987654324 的事实@,为什么不会有同样的效果? 有使用struct关键字的理由吗?在 C++ 中没有必要,除非 C 标头中存在一些我不知道的名称冲突?【参考方案3】:
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

请注意,如果是现有文件,则会以随机访问模式打开它。如果您愿意,可以将其关闭并以追加模式或截断模式重新打开。

【讨论】:

想想如果文件存在会发生什么,但用户没有读取它的访问权限。 @SasQ:是的......这绝对是一个黑客/解决方法。 C++17 中的正确解决方案是 std::filesystem::exists(),或者除非是 stat() @HighCommander4 “除此之外,stat()”?那是什么?你打算告诉我们什么? @John 如果您的标准库实现还不支持std::filesystem,您可以使用POSIX API 中的stat() 函数(Windows 也支持)【参考方案4】:
bool fileExists(const char *fileName)

    ifstream infile(fileName);
    return infile.good();

这种方法是迄今为止最短且最便携的方法。如果用法不是很复杂,这是我会选择的。如果你也想提示一个警告,我会在 main 中这样做。

【讨论】:

说明:使用 ifstream 构造函数尝试打开文件进行读取。当函数返回并且 ifstream 超出范围时,它的析构函数将隐式关闭文件(如果文件存在并且打开成功)。 除了它做错事:它检查一个文件是否可以打开,而不是它是否存在。如果访问权限不允许用户访问它,该函数将错误地声称该文件不存在,因为它将无法打开它进行读取。【参考方案5】:

其中一种方法是执行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

希望这会有所帮助。 谢谢!

【讨论】:

【参考方案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

【讨论】:

以上是关于std::ofstream,写入前检查文件是不是存在的主要内容,如果未能解决你的问题,请参考以下文章

大约 2Gb 后 C++ ofstream 写入性能下降

std::ofstream::write 添加字符

std::ofstream 无法在 win7/64 和 msvc2013 上使用 std::ios::ate 打开大文件

如何将 std::ofstream& 传递给功能参数?

通过 SWIG 在 python 中使用 std::ifstream、std::ofstream 的技术?

关于意外断电的原子写入