简体   繁体   English

流对象代表文件输入,然后代表标准输入?

[英]Stream object to represent file input and then standard input?

As a noob C++ project, I am building a CLI game with a game loop that relies upon user input. 作为一个noob C ++项目,我正在构建一个具有依赖用户输入的游戏循环的CLI游戏。 For the purpose of testing, I would like to be able to pass a file name as a command line argument to the program, which will be treated "like standard input" until it is read through. 为了进行测试,我希望能够将文件名作为命令行参数传递给程序,在将其读入之前,将其视为“标准输入”。

Consequently, I need a way to encapsulate an object that represents a file's contents and then std::cin once the file has been read through - basically prepending a file's contents to standard input. 因此,我需要一种方法来封装表示文件内容的对象, 然后在读取文件后封装std::cin基本上将文件的内容置于标准输入之前。 At least, this seems like it would be very nice, so that I can avoid having something like 至少,这看起来会很好,这样我就可以避免出现类似

std::istringstream retrieve_input(std::ifstream &file) {
  std::string line;
  if (std::getline(file, line))
    return std::istringstream{line};
  std::getline(std::cin, line);
  return std::istringstream{line};
}

Is replacing this with some kind of custom class a good approach? 用某种自定义类替换它是一种好方法吗? Or can I mess with std::cin somehow to prepend my file contents to it? 或者我可以以某种方式弄乱std::cin来添加我的文件内容吗?


To clarify : My game loop might have say, 20 iterations. 澄清一下:我的游戏循环可能有20次迭代。 If I pass a file with five lines, I want to use those five lines for the first five iterations of my game loop, and then drop back to standard input for the remaining fifteen. 如果我传递的文件有五行,我想在我的游戏循环的前五次迭代中使用这五行,然后在剩下的十五行中返回到标准输入。 I understand how to do this with a bunch of conditions, but I think there must be a way to nicely have this sort of behavior in a class. 我了解如何在很多条件下执行此操作,但是我认为必须有一种方法可以在类中很好地具有这种行为。 My problem is - what should it inherit from? 我的问题是-它应该继承什么? std::streambuf ? std::streambuf吗? Is this a good idea in principle? 原则上这是个好主意吗?

My (probably bad attempt) 我(可能是错误的尝试)

class InputGrabber {
public:
  virtual std::istringstream retrieve_line() = 0;
  virtual ~InputGrabber() {}
};

class BaseInputGrabber : public InputGrabber {
public:
  BaseInputGrabber(std::istream &_in): in{_in} {}
  std::istringstream retrieve_line() override {
    std::string line;
    std::getline(in, line);
    return std::istringstream{line};
  }

private:
  std::istream ∈
};

class VarInputGrabber : public InputGrabber {
public:
  VarInputGrabber(std::istream &_in, const std::string &f_name) :
    in{_in}, init{std::ifstream(f_name)} {}
  std::istringstream retrieve_line() override {
    std::string line;
    if (std::getline(init, line)) {
      return std::istringstream{line};
    }
    std::getline(in, line);
    return std::istringstream{line};
  }
private:
  std::istream ∈
  std::ifstream init;
};

Would the below work? 以下工作吗? You open the file, redirect std::cin to read from the file. 您打开文件,重定向std::cin以从文件中读取。 Use std::getline on std::cin so that it reads from the file stream. std::cin上使用std::getline ,以便它从文件流中读取。 Some time before the program ends or if the file is finished being read, restore std::cin back to its original state. 在程序结束之前的某个时间,或者如果文件读取完成,请将std::cin恢复到其原始状态。

#include <iostream>
#include <fstream>

int main(int argc, const char * argv[]) {

    std::fstream file("/users/Brandon/Desktop/testingInput.txt", std::ios::in);

    //Redirect cin to a file.
    std::streambuf* cinBuffer = std::cin.rdbuf();
    std::cin.rdbuf(file.rdbuf());

    //Read line from std::cin (which points to the file) with std::getline.
    std::string line;
    std::getline(std::cin, line);

    std::cout<<"INPUT LINE: "<<line<<std::endl;

    //Redirect cin to standard input.
    std::cin.rdbuf(cinBuffer);

    //Read some line from the user's input..
    std::getline(std::cin, line);
    std::cout<<"USER INPUT LINE: "<<line<<std::endl;
    std::cin.get();

    return 0;
}

You could always redirect from file via argv. 您始终可以通过argv从文件重定向。 Treat the whole thing as std::cin from the beginning. 从一开始就将整个事物视为std :: cin。

Is the following example that what you are looking for? 以下示例是您所寻找的吗?

std::string readNextLine(std::istream& is)
{
    std::string line;

    if(!std::getline(is, line))
        std::getline(std::cin, line);

    return line;
}

int main()
{
    std::stringstream ss ("a\nb\nc\n");

    for(int i = 0; i < 5; ++i)
    {
        auto line = readNextLine(ss);

        std::cout << "got: " << line << std::endl;
    }

    return 0;
}

The stringstream can be replaced with fstream or any other type that implements std::istream. 可以用fstream或实现std :: istream的任何其他类型替换stringstream。

You can test it here http://cpp.sh/5iv65 您可以在这里进行测试http://cpp.sh/5iv65

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM