【问题标题】:How can I read from memory just like from a file using iostream?如何从内存中读取,就像使用 iostream 从文件中读取一样?
【发布时间】:2010-12-03 14:01:53
【问题描述】:

我将简单的文本文件加载到内存中。我想从内存中读取,就像从光盘中读取一样:

ifstream file;
string line;

file.open("C:\\file.txt");
if(file.is_open())
{
    while(file.good())
    {
        getline(file,line);         
    }
}   
file.close();

但我在内存中有文件。我在内存中有一个地址和这个文件的大小。

我必须做什么才能像上面代码中处理文件一样流畅?

【问题讨论】:

标签: c++ memory iostream


【解决方案1】:

您可以执行以下操作..

std::istringstream str;
str.rdbuf()->pubsetbuf(<buffer>,<size of buffer>);

然后在您的getline 调用中使用它...

注意:getline 不理解 dos/unix 的区别,所以 \r 包含在文本中,这就是我为什么要咬它的原因!

  char buffer[] = "Hello World!\r\nThis is next line\r\nThe last line";  
  istringstream str;
  str.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
  string line;
  while(getline(str, line))
  {
    // chomp the \r as getline understands \n
    if (*line.rbegin() == '\r') line.erase(line.end() - 1);
    cout << "line:[" << line << "]" << endl;
  }

【讨论】:

  • 这就是我要找的!在istringstream 中放置此地址和大小的位置。但它不适用于getline...我检查了这个缓冲区,它是字符数组,新行是“\r\n”窗口样式。所以缓冲区没问题。我不知道该怎么做才能得到这条线。
  • 这段代码的一个问题:它不能保证工作。 pubsetbufbasic_streambuf 的影响是“实现定义的”。它还需要一个非常量指针,因此它可能会修改 putback 上的指向数据。
  • @ybungalobill:在这两点上都是错误的、正确的和正确的。但仍然无关紧要。 pubsetbuf(由 setbuf 调用)这是一个虚拟成员函数,应在派生类中重新定义以按预期运行,方法是将 s 指向的 n 个字符的数组设置为新的字符缓冲区。 重点补充。所以是的,它是由实现定义的,它是如何工作的(但定义的实现并不意味着它不会工作),它应该按预期工作。那么如果 putback 修改了缓冲区呢!我们正在传递一个可修改的数组,所以这应该不是问题。
  • @Martin:它是字符 buffer,预计用于缓冲文件、套接字、键盘、屏幕等的读写操作...不是预计将用作数据源。该标准并未规定任何流都应保留最初存在的数据。
  • @CichyK24:它不应该工作。标准不保证。有关详细信息,请参阅stackoverflow.com/questions/4349778/…。因此,如果您不想复制并且想要将其用作流的源,那么您可以做的最好的事情就是使用 boost。
【解决方案2】:

您可以为此使用istringstream

string text = "text...";
istringstream file(text);
string line;

while(file.good())
{
    getline(file,line);         
}

【讨论】:

  • 你是说 (i)stringstream 吗?
  • IIRC istrstream 已弃用。
  • 这需要将数据从字符串复制到字符串流缓冲区。所以@ybungalobill 建议的 Boost 解决方案会更快,但是这个解决方案会起作用,而且它不依赖于外部库。
  • 你的想法和尼姆基本一样。但是这个 veriant 实际上创建了一个从textfile 的数据副本。因此,如果文本很大(比如文件的内容,这可能是个问题)。
【解决方案3】:

使用 boost.Iostreams。特别是basic_array

namespace io = boost::iostreams;

io::filtering_istream in;
in.push(array_source(array, arraySize));
// use in

【讨论】:

  • STL 已支持该功能,因此无需使用 boost。
  • Martin,除了复制到 stringstream 之外,你能解释一下你使用数组作为 streambuf 的方式吗?
  • @Martin:STL 对此一无所知,无需复制数据。 Nim 的解决方案看起来不错,但不幸的是,查看标准我发现它至多是“定义的实现”。
  • pubsetbuf(由 setbuf 调用)这是一个虚拟成员函数,应在派生类中重新定义以按预期运行,方法是设置由 n 个字符组成的数组s 作为新的字符缓冲区。 强调。所以是的,它是实现定义了它的工作方式,但它应该按预期工作。
  • @Martin:它是字符缓冲区,预计将用于缓冲文件、套接字、键盘、屏幕等的读写... 预计不会使用作为数据源。该标准并未规定任何流都应保留最初存在的数据。
【解决方案4】:

我找到了一个适用于 VC++ 的解决方案,因为 Nim 解决方案仅适用于 GCC 编译器(非常感谢。感谢您的回答,我找到了其他对我有帮助的答案!)。

似乎其他人也有类似的问题。我完全按照herehere 做的。

因此,要像形成 istream 一样从内存中读取,您必须这样做:

class membuf : public streambuf
{
    public:
        membuf(char* p, size_t n) {
        setg(p, p, p + n);
    }
};

int main()
{
    char buffer[] = "Hello World!\nThis is next line\nThe last line";  
    membuf mb(buffer, sizeof(buffer));

    istream istr(&mb);
    string line;
    while(getline(istr, line))
    {
        cout << "line:[" << line << "]" << endl;
    }
}

编辑:如果您有 '\r\n' 新行,请按照 Nim 所写:

if (*line.rbegin() == '\r') line.erase(line.end() - 1);

我试图将此内存视为wistream。有人知道怎么做这个吗?我为此单独询问了question

【讨论】:

  • 我正在写IE插件,效率很重要,所以它不会弹出一个窗口提示禁用它,因为它很慢。如果我正在编写“普通”应用程序,我当然不会介意任何外部库:)
【解决方案5】:

使用

std::stringstream

它有一个接口来操作和读取字符串,就像其他流一样。

【讨论】:

    【解决方案6】:

    我会这样做:

    #include <sstream>
    
    std::istringstream stream("some textual value");
    std::string line;
    while (std::getline(stream, line)) {
        // do something with line
    }
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-23
      • 2017-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多