2016-12-01 89 views
0

我正在和一位同事讨论,我认为这将是一个很好的问题放在这里。文件或流的路径?

当设计API时,你的函数应该接受文件路径,什么时候应该接受流?有没有任何指导方针?

void do_something(const std::filesystem::path &file_path); 
void do_something(std::istream &stream); 

路径:

  • 被叫负责检查该文件存在并且可以访问。
  • 很难进行单元测试。你必须在磁盘上创建/拥有一个文件来测试它。

流:

  • 来电者是负责检查该文件存在并且可以访问。更多重复的样板代码。
  • 单元测试更容易,你可以只通过一个流对象

我想一个可能的功能添加到库中,以“帮助”打开文件时,各种各样的东西:

std::ifstream open_input(const std::filesystem::path &file) 
{ 
    std::ifstream stream(file); 

    if (not stream) { 
     throw std::invalid_argument("failed to open file: " + file.string()); 
    } 

    return stream; 
} 
+0

我个人一直使用的路径,因为这样我可以检查的类型,如“.TXT” –

+0

恐怕这个问题将被封闭,过于宽泛或基于观点。尽管如此,我更喜欢第二个版本,因为它更灵活(可以与其他流一起使用),并且服从SRP。事实上,我会考虑更进一步,并创建一个基于API迭代器的。 – user58697

+0

@ user58697处理文件时基于迭代器? – Mac

回答

0

你自己说过,你可以添加“助手”功能来保存istream接口。这在测试性方面也是更好的解决方案,并遵守单一责任原则(SRP)。

你的帮助函数有一个责任(从文件创建流)和另一个实际函数(它“做某事”:))。

我想补充一点,它取决于实际做的事情的背景。例如,如果它是一个facade用于对基础功能的不同访问,那么将该接口与实际路径相关联是有意义的。你仍然会有一个独立的帮助函数和一个do_something函数,这些函数从外观中使用。

0

你可能有你的鱼与熊掌兼得:

#include <fstream> 
#include <sstream> 
#include <utility> 

// 
// some booilerplate to allow use of a polymorphic temporary 
template<class Stream, std::enable_if_t<std::is_base_of<std::istream, Stream>::value> * = nullptr> 
struct stream_holder 
{ 
    stream_holder(Stream stream) : stream_(std::move(stream)) {} 
    operator std::istream&() && { return stream_; } 
    operator std::istream&() & { return stream_; } 

    private: 
    Stream stream_; 
}; 

// helper function 
template<class Stream, std::enable_if_t<std::is_base_of<std::istream, Stream>::value> * = nullptr> 
auto with_this(Stream&& stream) 
{ 
    return stream_holder<std::decay_t<Stream>>(std::forward<Stream>(stream)); 
} 



// express logic in terms of stream 
void do_something(std::istream& stream_ref); 

// utility functions to create various types of stream 
std::ifstream file_stream(); 
std::stringstream string_stream(); 


int main() 
{ 

    // * composability with succinct syntax 
    // * lifetime automatically managed 
    // * no repetitive boilerplate 
    do_something(with_this(file_stream())); 
    do_something(with_this(string_stream())); 
}