首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以可移植的方式读取C++中的文件并处理可能的错误

以可移植的方式读取C++中的文件并处理可能的错误
EN

Stack Overflow用户
提问于 2017-08-23 21:09:40
回答 4查看 4.2K关注 0票数 16

我想做一件简单的事情:读取文件中的第一行,如果没有这样的文件,没有读取文件的权限等等,就做一个适当的错误报告。

我考虑了以下选项:

  • std::ifstream.不幸的是,没有可移植的方法来报告系统错误。其他一些答案建议在读取失败后检查errno,但标准不保证iostreams库中的任何函数都设置了errno
  • C样式iostreams这是可行的,但不像使用std::getline的iostreams那么方便。我正在寻找C++解决方案。

有没有办法使用C++14和boost来实现这一点?

EN

回答 4

Stack Overflow用户

发布于 2017-08-24 01:40:40

免责声明:我是AFIO的作者。但你要找的正是https://ned14.github.io/afio/,它是v2库,包含了2015年8月Boost同级评审的反馈。See the list of features here

当然,我要提醒的是,这是一个alpha质量的库,您不应该在生产代码中使用它。然而,已经有相当多的人这样做了。

如何使用AFIO解决OP的问题:

注意,AFIO是一个非常低级的库,因此你必须输入更多的代码来实现与iostream相同的功能,另一方面,你没有内存分配,没有异常抛出,没有不可预测的延迟尖峰:

代码语言:javascript
复制
  // Try to read first line from file at path, returning no string if file does not exist,
  // throwing exception for any other error
  optional<std::string> read_first_line(filesystem::path path)
  {
    using namespace AFIO_V2_NAMESPACE;
    // The result<T> is from WG21 P0762, it looks quite like an `expected<T, std::error_code>` object
    // See Outcome v2 at https://ned14.github.io/outcome/ and https://lists.boost.org/boost-announce/2017/06/0510.php

    // Open for reading the file at path using a null handle as the base
    result<file_handle> _fh = file({}, path);
    // If fh represents failure ...
    if(!_fh)
    {
      // Fetch the error code
      std::error_code ec = _fh.error();
      // Did we fail due to file not found?
      // It is *very* important to note that ec contains the *original* error code which could
      // be POSIX, or Win32 or NT kernel error code domains. However we can always compare,
      // via 100% C++ 11 STL, any error code to a generic error *condition* for equivalence
      // So this comparison will work as expected irrespective of original error code.
      if(ec == std::errc::no_such_file_or_directory)
      {
        // Return empty optional
        return {};
      }
      std::cerr << "Opening file " << path << " failed with " << ec.message() << std::endl;
    }
    // If errored, result<T>.value() throws an error code failure as if `throw std::system_error(fh.error());`
    // Otherwise unpack the value containing the valid file_handle
    file_handle fh(std::move(_fh.value()));
    // Configure the scatter buffers for the read, ideally aligned to a page boundary for DMA
    alignas(4096) char buffer[4096];
    // There is actually a faster to type shortcut for this, but I thought best to spell it out
    file_handle::buffer_type reqs[] = {{buffer, sizeof(buffer)}};
    // Do a blocking read from offset 0 possibly filling the scatter buffers passed in
    file_handle::io_result<file_handle::buffers_type> _buffers_read = read(fh, {reqs, 0});
    if(!_buffers_read)
    {
      std::error_code ec = _fh.error();
      std::cerr << "Reading the file " << path << " failed with " << ec.message() << std::endl;
    }
    // Same as before, either throw any error or unpack the value returned
    file_handle::buffers_type buffers_read(_buffers_read.value());
    // Note that buffers returned by AFIO read() may be completely different to buffers submitted
    // This lets us skip unnecessary memory copying

    // Make a string view of the first buffer returned
    string_view v(buffers_read[0].data, buffers_read[0].len);
    // Sub view that view with the first line
    string_view line(v.substr(0, v.find_first_of('\n')));
    // Return a string copying the first line from the file, or all 4096 bytes read if no newline found.
    return std::string(line);
  }
票数 18
EN

Stack Overflow用户

发布于 2019-01-21 05:11:43

boost-users邮件列表上的人指出,boost.beast库具有用于基本文件IO 的独立于操作系统的应用程序接口,包括适当的错误处理file concept有三种开箱即用的实现: POSIX、stdio和win32。实现支持RAII (销毁时自动关闭)和移动语义。POSIX文件模型自动处理EINTR错误。基本上,这对于可移植地逐块读取文件块以及例如显式地处理缺少文件的情况是足够和方便的:

代码语言:javascript
复制
using namespace boost::beast;
using namespace boost::system;

file f;
error_code ec;
f.open("/path/to/file", file_mode::read, ec);
if(ec == errc::no_such_file_or_directory) {
    // ...
} else {
    // ...
}
票数 1
EN

Stack Overflow用户

发布于 2017-08-24 05:58:45

代码语言:javascript
复制
#include <iostream>
#include <fstream>
#include <string>
#include <system_error>

using namespace std;

int
main()
{
    ifstream f("testfile.txt");
    if (!f.good()) {
        error_code e(errno, system_category());
        cerr << e.message();
        //...
    }
    // ...
}

ISO C++标准:

报头"cerrno“的内容与POSIX报头"errno.h”相同,不同之处在于errno应定义为宏。注意:其目的是保持与POSIX标准的紧密一致。- end note应为每个线程提供单独的errno值。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45840686

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档