【问题标题】:Write a collection to a binary file将集合写入二进制文件
【发布时间】:2016-05-03 09:22:22
【问题描述】:

我正在寻找一种将一些数据(List、Array 等)写入二进制文件的方法。放入二进制文件的集合表示点列表。我到现在为止的尝试: [

11:17]
Welcome to Scala 2.12.0-M3 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_40).
Type in expressions for evaluation. Or try :help.

scala> import java.io.{FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream}
import java.io.{FileInputStream, FileOutputStream, ObjectInputStream, ObjectOutputStream}

scala> val oos = new ObjectOutputStream(new FileOutputStream("/tmp/f1.data"))
oos: java.io.ObjectOutputStream = java.io.ObjectOutputStream@13bc8645

scala> oos.writeObject(List(1,2,3,4))

scala> oos.close

scala> val ois = new ObjectInputStream(new FileInputStream("/tmp/f1.data"))
ois: java.io.ObjectInputStream = java.io.ObjectInputStream@392a04e7

scala> val s : List[Int] = ois.readObject().asInstanceOf[List[Int]]
s: List[Int] = List(1, 2, 3, 4)

好的,它运行良好。问题是,也许明天我需要用另一种语言作为Python 来读取这个二进制文件。是否有一种更通用的二进制文件可以被多种语言读取的方法?

解决方案

对于在相同情况下搜索的人,您可以这样做:

def write2binFile(filename : String, a : Array[Int]) = {
      val inChannel = new RandomAccessFile(filename, "rw").getChannel
      val bbufer = ByteBuffer.allocateDirect(a.length * 4)
      val ibuffer = bbufer.asIntBuffer()
      ibuffer.put(a)
      inChannel.write(bbufer)
      inChannel.close
    }

【问题讨论】:

  • 你想使用二进制的原因是什么?是使文件变小还是隐藏其内容?在我的脑海中,BSON 听起来像是一种你可能会考虑的格式。不确定 Scala/Python 中的库支持,但一定有一些东西,因为 MongoDB 使用这种格式。
  • 原因是我想将二进制文件存储在 Amazon S3 上并使用 aws java API 读取特定范围的字节。所以二进制文件不能特定于Java,这是我发帖的主要原因。
  • 这取决于二进制格式,根据您的描述,您还需要某种索引或至少一种计算方法来知道哪些元素存储在哪个字节索引处?对于跨语言二进制序列化,我建议看看 Google Protobuffers。但是根据您的用例,您可能需要一些不同的东西来使您的字节查找工作。
  • 投票结束为“过于广泛”。有很多方法可以做到这一点,并且许多格式可能会起作用。它也可能被认为是这个问题的重复:stackoverflow.com/questions/1421707/…
  • @ElmarWeber,我有一个 JSON 文件描述了每个二进制文件(样本数,开始时间)。选择格式是我可以使用 AWS Java API 轻松提取的字节序列。主要问题是是否有另一种方法可以将我的数据写入二进制文件。

标签: python scala binaryfiles


【解决方案1】:

点坐标的跨平台共享格式允许通过 RANGE 选择性访问

您的要求是:

  • 由 Scala 存储数据,由 Python(或其他语言)读取
  • 数据是点坐标列表
  • 将数据存储在 AWS S3 上
  • 允许使用 RANGE 请求仅获取部分数据

要使用的数据结构

每个元素的数据必须在结构和大小上保持一致,以允许通过 RANGE 计算某个部分的位置。

如果存储列表/数组的 Scala 格式满足这个要求,并且如果 二进制格式定义明确,你可能会成功。如果没有,你必须找到 另一种格式。

用Python读取二进制数据

假设格式是已知的,使用来自 stdlib 的 Python struct 模块来读取它。

替代方法:将数据拆分为更小的部分

您愿意逐个访问数据,可能期望 S3 上有一个大对象并使用带有 RANGE 的 HTTP 请求。

另一种解决方案是将数据分成较小的块,这些块具有合理的大小以供获取(例如 64 kB,但您更了解您的用例),并设计规则将它们逐块存储在 AWS S3 上。您甚至可以为此使用树形结构。

这种方法有一些优点:

  • 使用您喜欢的任何格式,例如XML、JSON,无需处理特殊的二进制格式
  • 件可以压缩,您会节省一些成本

请注意,AWS S3 不仅会向您收取数据传输费用,还会按请求收取费用,因此每个使用 RANGE 的 HTTP 请求都将计为一次。

需要考虑的跨平台二进制格式

考虑以下格式:

  • BSON
  • (谷歌)结果缓冲区
  • HDF5

如果您访问任何这些格式的 Wikipedia 页面,您会发现许多指向其他格式的链接。

无论如何,我不知道任何这样的格式,它们会使用每个元素的统一尺寸,因为它们中的大多数都试图保持尽可能小的尺寸。因此,除非引入一些特殊的索引文件(这可能不太可行),否则它们不能在使用 RANGE 的场景中使用。

另一方面,通过其他方法使用这些格式(拆分 数据到更小的部分)应该可以工作。

注意:我过去做过一些关于存储效率和编码/解码速度的测试。从实际的角度来看,最好的结果是使用简单的 JSON 结构(可能是压缩的)实现的。您在每个平台上都可以找到这些选项,使用起来非常简单,编码/解码速度很高(我不是说最高的)。

【讨论】:

  • 我不认为这真的回答了这个问题,因为:“假设格式是已知的”,然后这个“使用来自 stdlib 的 Python struct 模块来读取它。”,给定 OP谈论“多种语言”。 “替代品”基本上只是说“自己动手”。
  • @TheArchetypalPaul 感谢您对投票的反馈。问题是,什么是真正的问题,并且在标题、问题文本和 cmets 阐明其背后的真正内容之后,它通常会有所不同。我说的是最后一个。无论如何,我在我的答案中添加了解决格式及其可用性的部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-30
  • 1970-01-01
相关资源
最近更新 更多