【问题标题】:How to read efficiently from an stdin pipe data that need seeking如何从需要查找的标准输入管道数据中高效读取
【发布时间】:2012-05-07 11:15:07
【问题描述】:

我正在寻找在 C 编程中从 stdin 管道读取数据的最佳方法。

问题:我需要寻找这些数据,即在同一流的end读取一些数据后,我需要从流的start读取数据.

小用例:gunzip -c 4GbDataFile.gz | myprogram

另一个:

  1. 在本地主机上:nc -l -p 1234 | myprogram
  2. 在远程主机上:gunzip -c 4GbDataFile.gz | nc -q 0 theotherhost 1234

我知道从 fifo 读取只能执行一次。所以,目前:

  • 我从stdin 到内存slurp所有内容,并在分配的内存中工作。

它很丑,但它有效。一个明显的问题是,如果有人向我的应用程序发送一个巨大的(或连续的)流,我将以分配的大内存块结束,否则我将耗尽内存。 (考虑一个 8Gb 的文件)

我接下来的想法:

  • 我设置了该内存块的大小限制(可能是用户定义的)。一旦我从 stdin 读取了这么多数据:
    1. 要么我停在这里:“错误。内存不足,bazinga。算了吧。”风格。
    2. 我要么开始转储我正在读取的内容到一个文件,然后在读取所有数据后从该文件开始工作。

但是,那有什么意义呢?我无法找出我正在阅读的数据的来源。如果这是一个本地 8Gb 文件,我会将其转储到同一系统上的另一个 8Gb 文件中。

所以,我的问题是:

当您必须在stdinpipe 中来回查找时,如何高效地读取大量数据?

提前感谢您的回答。

编辑:

我的程序需要在给定文件的某处(取决于文件格式)读取元数据,因此可能在流的末尾。然后它可能会在流的开头读回其他数据,然后在另一个地方等。简而言之:它需要访问数据的任何字节。

一个例子是在从stdin开始读取之前在不知道文件格式的情况下读取存档文件的数据:我需要检查存档元数据,查找存档文件名称和偏移量等。

所以我将制作标准输入内容的本地副本并使用它。感谢大家的投入;)

【问题讨论】:

  • ITYM myprogram < 4GbDataFile。目前,cat 4GbDataFile > myprogram 会覆盖您的程序二进制文件。当你用管道替换 '>' 时,你对 cat 的使用毫无用处。
  • 谢谢,修正了错字,增加了对 cat 的更有用的用法。

标签: c file memory stdin


【解决方案1】:

您需要明确您的要求。如果您需要seek(),那么显然您不能从stdin 获取输入。如果您需要seek(),那么您应该将输入文件名作为参数。

【讨论】:

  • 我提到过,目前,它的工作原理是把所有内容都存入内存并在这里完成工作。我想它在使用临时文件时也会起作用。我知道我无法在 fifo 上寻找,我正在寻找一种优雅的(不仅仅是我的啜饮)解决方法;)
  • 我想它会在使用临时文件时起作用。 -- 但是,当您只是复制文件内容时,为什么要这样做呢?你的程序是做什么的?
  • 我的程序需要在给定文件的某处(取决于文件格式)读取元数据,因此可能在流的末尾。然后它可能会在流的开头读回其他数据,然后在另一个地方等。简而言之,它需要访问数据的任何字节。一个例子是读取存档文件的数据 不知道文件格式:我需要检查存档元数据,查找存档文件名称和偏移量等。
  • 因此,如果您的程序在 文件 上运行,则将它们视为文件,即从任何位置查找和读取它们。
  • 除了stdin不是一个普通的文件,不是吗?我不能像往常一样寻找或阅读它。这就是为什么我目前将从标准输入读取的数据映射到内存(或文件,但如果 $user 只是将本地文件添加到我的程序,我将复制文件而不是处理原始文件...... )。这行得通,如果 $user 向我发送很多数据,我正在寻找一种优雅的回退方式。
【解决方案2】:

4GbDataFile 中的数据结构不适合您想要做的事情。创造性思考。不要将你的程序锤炼成它甚至不应该尝试的东西。尝试修复生成它的输入格式,这样您就不需要回溯 4 GB。

如果您确实喜欢锤击:4GB 的核心内存相当昂贵。相反,将从标准输入读取的数据保存在一个文件中,然后打开该文件(或对其进行映射)并寻找您想要的内容。

【讨论】:

  • 我无法修复输入格式,因为它可以是任何东西(我编辑了我的问题并在最后添加了一个程序工作示例)。不映射 4GB 文件会导致 4GB 内核内存块吗?将读取的数据保存到文件中并在其中查找可能更合适,但如果它是本地文件,它只是复制原始文件并处理副本而不是原始文件......
  • 你不能吃你的馅饼。寻找管道是不可能的。如果您坚持这样做,则必须将不可搜索的数据变成可搜索的(通过保存副本)。在映射时,不要映射整个数据,只需将要查找的块映射到,根据查找偏移量计算。
  • 好的,谢谢,我会制作一份副本,并警告用户不要管道巨大的本地文件,并且更愿意将它们作为 fd 提供以避免重复内容。
【解决方案3】:

我认为你应该阅读臭名昭著的Useless Use of Cat Award

TL;DR:将 cat 4gbfile | yourprogram 更改为 yourprogram < 4gbfile

如果你真的坚持让它处理来自管道的数据,你必须在启动时将它存储在一个临时文件中,然后使用 dup2 将文件描述符 0 替换为临时文件的 fd 副本.

【讨论】:

  • 这就是我想要的:处理来自管道的数据。 (编辑我的问题以删除“无用的猫”,顺便说一下,这只是一个例子......否则我会使用你和@Jens推荐的)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-08
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多