由于某种原因,我需要非常大的,甚至可能是无限的InputStream ,它会反复地反复返回相同的byte[] 。 这样,我可以通过重复小样本来产生大量的数据流。 在Guava中可以找到类似的功能: Iterable<T> Iterables.cycle(Iterable<T>)Iterator<T> Iterators.cycle(Iterator<T>) 。 例如,如果您需要01的无限来源,只需说出Iterables.cycle(0, 1)并无限获取Iterables.cycle(0, 1) 0, 1, 0, 1, 0, 1... 不幸的是,我还没有为InputStream找到这样的工具,所以我跳入自己编写的工具。 本文记录了我在此过程中犯的许多错误,主要是由于过于复杂和过度设计的简单解决方案。

我们实际上不需要无限的InputStream ,能够创建非常大的InputStream (例如32 GiB)就足够了。 因此,我们采用以下方法:

public static InputStream repeat(byte[] sample, int times)

它基本上采用字节sample数组,并返回一个InputStream返回这些字节。 但是,当sample用完时,它将翻转,再次返回相同的字节-重复此过程指定的次数,直到InputStream信号结束。 我尚未真正尝试过但似乎最明显的一种解决方案:

public static InputStream repeat(byte[] sample, int times) {final byte[] allBytes = new byte[sample.length * times];for (int i = 0; i < times; i++) {System.arraycopy(sample, 0, allBytes, i * sample.length, sample.length);}return new ByteArrayInputStream(allBytes);
}

我看到你在那里笑! 如果sample是100字节,并且我们需要32 GiB的输入重复这100字节,则生成的InputStream不应真正分配32 GiB的内存,我们在这里必须更加聪明。 事实上,上面的repeat()有另一个细微的错误。 Java中的数组限制为2 31 -1个条目( int ),而32 GiB远高于此。 该程序编译的原因是此处无声的整数溢出: sample.length * times 。 此乘法不适用于int

好的,让我们尝试至少在理论上可行的方法。 我的第一个想法是:如果我创建许多ByteArrayInputStream共享同一byte[] sample (它们不进行急切的复制)并以某种方式将它们连接在一起怎么办? 因此,我需要一些InputStream适配器,该适配器可以采用任意数量的基础InputStream并将它们链接在一起-当第一个流耗尽时,切换到下一个。 当您在Apache Commons或Guava中寻找某些东西,并且显然永远在JDK中时,这一尴尬时刻…… java.io.SequenceInputStream几乎是理想的选择。 但是,它只能精确地链接两个基础InputStream 。 当然,由于SequenceInputStream本身就是InputStream ,我们可以递归地将其用作外部SequenceInputStream的参数。 重复此过程,我们可以将任意数量的ByteArrayInputStream在一起:

public static InputStream repeat(byte[] sample, int times) {if (times <= 1) {return new ByteArrayInputStream(sample);} else {return new SequenceInputStream(new ByteArrayInputStream(sample),repeat(sample, times - 1));}
}

如果times为1,则将sample包装在ByteArrayInputStream 。 否则,递归使用SequenceInputStream 。 我认为您可以立即发现此代码的问题:太深的递归。 嵌套级别与times参数相同,将达到数百万甚至数十亿。 肯定有更好的办法。 幸运的是,较小的改进将递归深度从O(n)更改为O(logn):

public static InputStream repeat(byte[] sample, int times) {if (times <= 1) {return new ByteArrayInputStream(sample);} else {return new SequenceInputStream(repeat(sample, times / 2),repeat(sample, times - times / 2));}
}

老实说,这是我尝试的第一个实现。 这是分而治之原理的简单应用 ,在这里我们将结果平均分成两个较小的子问题。 看起来很聪明,但是有一个问题:容易证明我们创建了t( t =timesByteArrayInputStreams和O(t) SequenceInputStream 。 共享sample字节数组时,数百万个各种InputStream实例浪费了内存。 这使我们另一种实现,创建只有一个InputStream ,无论价值times

import com.google.common.collect.Iterators;
import org.apache.commons.lang3.ArrayUtils;public static InputStream repeat(byte[] sample, int times) {final Byte[] objArray = ArrayUtils.toObject(sample);final Iterator<Byte> infinite = Iterators.cycle(objArray);final Iterator<Byte> limited = Iterators.limit(infinite, sample.length * times);return new InputStream() {@Overridepublic int read() throws IOException {return limited.hasNext() ?limited.next() & 0xFF :-1;}};
}

毕竟,我们将使用Iterators.cycle() 。 但是在我们必须将byte[]转换为Byte[]因为迭代器只能与objets一起使用,而不能与原语一起使用。 没有惯用的方法ArrayUtils.toObject(byte[])语数组转换为盒装类型数组,因此我使用来自Apache Commons Lang的ArrayUtils.toObject(byte[]) 。 有了对象数组,我们可以创建一个infinite迭代器,循环遍历sample值。 由于我们不需要无限的流,因此再次使用了来自Guava的Iterators.limit(Iterator<T>, int)来切断无限迭代Iterators.limit(Iterator<T>, int) 。 现在我们只需要从Iterator<Byte>InputStream进行桥接–毕竟它们在语义上代表着同一件事。

该解决方案遭受两个问题。 首先,由于拆箱,它会产生大量垃圾。 垃圾收集并不太关心死的,短命的物品,但看起来仍然很浪费。 我们之前已经遇到的第二个问题: sample.length * times乘以倍数可能会导致整数溢出。 由于Iterators.limit()占用intlong ,因此没有固定的理由,因此无法修复。 顺便说一句,我们通过做按位避免第三个问题0xFF -否则, byte值为-1将信号流的结束,这是情况并非如此。 x & 0xFF被正确转换为无符号255int )。

因此,即使上面的实现是简短而甜美,声明式而不是命令式的,但它仍然太慢且受限制。 如果您具有C背景,我可以想象您看到我挣扎时会感到多么不舒服。 在我最后想到的是最简单,痛苦的简单和低级实现之后:

public static InputStream repeat(byte[] sample, int times) {return new InputStream() {private long pos = 0;private final long total = (long)sample.length * times;public int read() throws IOException {return pos < total ?sample[(int)(pos++ % sample.length)] :-1;}};
}

免费的GC,纯JDK,快速且易于理解。 给您上一课:从您想到的最简单的解决方案开始,不要过度设计,也不要太聪明。 我以前的解决方案(声明性,功能性,不变性等)–也许它们看起来很聪明,但是它们既不快速也不容易理解。

我们刚刚开发的实用程序不仅是一个玩具项目,还将在后续文章中使用 。

翻译自: https://www.javacodegeeks.com/2014/07/building-extremely-large-in-memory-inputstream-for-testing-purposes.html

构建用于测试的超大型内存InputStream相关推荐

  1. 输入流输出流是以内存为标准_构建用于测试的超大内存输入流

    输入流输出流是以内存为标准 由于某种原因,我需要非常大的,甚至可能是无限的InputStream ,它会反复地反复返回相同的byte[] . 这样,我可以通过重复小样本来产生疯狂的大数据流. 可以在G ...

  2. 推荐11个构建和测试API的顶级工具

    点击蓝色"程序猿DD"关注我 回复"资源"获取独家整理的学习资料! >> 「开学季」当当大促!4-5折优惠不了解一下? << 立刻像专业 ...

  3. 构建、测试和部署驱动程序

    Visual Studio Community 2015 RC 与 Windows 驱动程序工具包 (WDK) 10 配合使用,可提供为运行 Windows 10 的设备创建高效.优质驱动程序的集成式 ...

  4. Jenkins-自动化构建、测试和部署-学习笔记

    来源于黑马程序员jenkins文档笔记 1.Jenkins介绍 Jenkins 是一款流行的开源持续集成(Continuous Integration)工具,广泛用于项目开发,具有自动 化构建.测试和 ...

  5. undertow服务器分析_使用undertow构建和测试Websocket服务器

    undertow服务器分析 即将发布的JBoss Application Server版本将不再使用Tomcat作为集成的Web服务器,而是将其替换为undertow . undertow的体系结构基 ...

  6. 构建忽略测试_分类测试以减少构建时间

    构建忽略测试 在继续本文的主要内容之前,让我们先进行一些定义. 单元测试 单元测试是小型的(测试一个用例或一个单元),在内存中运行(不与数据库,消息队列等交互),可重复且快速的测试. 对于我们的对话, ...

  7. android bench内存测试,华为p10内存测试软件(androbench) v5.0.1 免费版

    华为p10内存测试软件(androbench)其实是androbench这款内存测试软件,可以用于测试你的华为p10,是一款不错的华为p10内存测试软件,可以测试你的手机闪存性能,其他的手机也可以免费 ...

  8. evil twin_Evil-Twin框架:用于测试WiFi安全性的工具

    evil twin 越来越多的设备通过无线方式通过无线方式连接到Internet,以及WiFi接入点的广泛可用性,为攻击者提供了许多利用用户的机会. 通过诱骗用户连接到恶意访问点 ,黑客可以完全控制用 ...

  9. 第一个云原生步骤:自动化构建、测试和部署(二)

    目录 设置项目 创建构建管道 使用TypeScript创建Azure Function 这个怎么运作 发布管道 下一步 下载源文件 - 8.1 KB 云原生开发不仅仅涉及在云中运行代码.正如我们在本系 ...

最新文章

  1. Python基础12-常用的内置函数
  2. 一 梳理 从 HDFS 到 MR。
  3. CMake 条件判断
  4. 浅谈 G1 GC 日志格式
  5. html5 控制鼠标移动,HTML5 Canvas随鼠标移动的引力粒子群
  6. cuba 平台_CUBA平台正在开源
  7. MyBatis之输入(parameterType)与输出(resultType、resultMap)映射
  8. 这是一则计算机视觉顶级会议CVPR与腾讯的爆闻,啥?
  9. Vue深入学习1—mustache模板引擎原理
  10. Precedence Problems of C Operators
  11. 如果把Python代码写成这样子就太难看了
  12. 如何把报表放到网页中显示(Web页面与报表简单集成例子)
  13. RHEL6 Tiny Linux 的制作
  14. 编码器正反转识别方法
  15. mysql查询字段为null的方法
  16. 使用netron对mnist网络结构分析
  17. dxp中发光二极管在哪找_DXP2004 元件库中常用元件
  18. java 校验 签名_使用JAVA实现签名验证示例程序详解
  19. Stm32 SRAM 启动方法
  20. Python3基础知识

热门文章

  1. MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established
  2. 气泡提示效果css.html,用纯CSS3绘制高端简约的气泡提示框
  3. excel如何生成mysql的sql语句_excel 批量生成SQL语句
  4. Linux 临时表空间满了,Temporary表空间100%解决方案
  5. React学习途径和资料分享
  6. Sprng boot(十三):Spring boot 小技巧
  7. 纯干货,Spring-data-jpa详解,全方位介绍。
  8. java编写排序的代码_在Java 8之前,您编写了几行代码来对对象集合进行排序?...
  9. java异步接口转同步接口_如果今天设计了Java:同步接口
  10. sidecar_Spring Cloud Sidecar –节点初始化