简体   繁体   English

如何在Java中将二进制文件转换为对象

[英]How to convert binary file to object in java

I've got a binary format file, that I want to turn into Java objects and then finally output that into CSV format. 我有一个二进制格式的文件,我想将其转换为Java对象,然后最终将其输出为CSV格式。

I've started going down a route, that although I know will work, seems incorrect. 我已经开始沿着一条路线走了,尽管我知道那行得通,但似乎不正确。

Can someone please either tell me this is the way to do this, or suggest alternatives. 有人可以告诉我这是这样做方法,还是建议其他方法。

Sample code below: 下面的示例代码:

    public class Baf5014Converter 
    {
        //private recordSize

        public Baf5014 convertBytesToObject(byte[] bafRecordInBytes) {

            Baf5014 record = new Baf5014();
            record.setSize(getRecordSize(bafRecordInBytes));

            return record;
        }

        private int getRecordSize(byte[] bafRecordInBytes)
        {
            byte[] recordSizeInBytes = Arrays.copyOfRange(bafRecordInBytes,0,2);
            return ByteBuffer.wrap(recordSizeInBytes).getShort();
        }
}

The idea would be to create a number of different getFoo functions as I go through the file. 我的想法是在浏览文件时创建许多不同的getFoo函数。 What I don't particularly like already is the magic numbers 0,2 in the above, even if the function name I guess makes it obvious enough what it's doing. 我不特别喜欢的是上面的魔术数字0,2,即使我猜想的函数名称已经很清楚它在做什么,也是如此。

Googling hasn't helped so far, but it might be that I don't know the right words to search for :) 谷歌搜索到目前为止还没有帮助,但可能是我不知道要搜索的正确单词:)

Any help would be greatly appreciated, 任何帮助将不胜感激,

Cheers 干杯

Alan 艾伦

There's no "one true" approach to this, and yours is OK. 没有“一个真实的”方法,您的还可以。 There's nothing wrong with "magic numbers" - they simply correspond to magic numbers in the file format you are reading. “魔术数字”没有什么错-它们只是与您正在读取的文件格式中的魔术数字相对应。 It's probably a good idea to make the magic numbers constants, for readability. 为了提高可读性,使魔术数字常量成为一个好主意。

One approach you might take is to have a class with an InputStream as a constructor parm. 您可能采取的一种方法是使用一个具有InputStream的类作为构造函数。

 public MyObj(InputStream binaryStream) {
     Scanner scanner = new Scanner(binaryStream);
     this.recordSize = scanner.nextShort();
     ...
 }

Then to create objects: 然后创建对象:

FileInputStream fis = new FileInputStream(file);
MyObj obj = new MyObj(fis);

Why not have File as a constructor arg? 为什么不使用File作为构造函数arg? Well, because it's much easier to write unit tests that supply a ByteArrayInputStream, than it is to create files as part of unit tests. 好吧,因为编写提供ByteArrayInputStream的单元测试要比创建文件作为单元测试的一部分容易得多。

Scanner is one class that will help you convert a stream of bytes into higher level types. Scanner是一类,可帮助您将字节流转换为更高级别的类型。 DataInputStream is another -- see which one suits your needs. DataInputStream是另一种-看看哪一种适合您的需求。

The approach you take will be guided by the format of the data. 您采用的方法将以数据格式为指导。 The easiest formats to use can be read by streaming - just chew through the stream handling each part as it comes. 可以通过流读取最容易使用的格式-只需仔细检查流中处理的各个部分即可。 Some formats are awkward in that some crucial attribute you need before you start, is stored at the end of the file. 某些格式很尴尬,因为您需要在开始之前将一些关键属性存储在文件末尾。 In that case, you have to either: 在这种情况下,您必须:

  • read through the stream twice or more 仔细阅读流两次或更多次
  • read the whole stream into memory, then work with the byte[] 将整个流读取到内存中,然后使用byte[]
  • open a mapped file with NIO FileChannel.map() to arbitrarily read bytes in any position. 使用NIO FileChannel.map()打开一个映射文件,以任意位置读取字节。

Another approach is to use Java's Serializable interface, and define your own writeObject and readObject methods to use the binary format you prefer. 另一种方法是使用Java的Serializable接口,并定义自己的writeObject和readObject方法以使用您喜欢的二进制格式。

Your approach seems ok to me. 您的方法对我来说似乎还可以。 You will have to adhere to the data structure of the file so magic numbers are unavoidable. 您将必须遵守文件的数据结构,因此不可思议的数字是不可避免的。

You could avoid using those numbers in the helper functions by moving them up one level. 您可以通过将其上移一级来避免在辅助功能中使用这些数字。 I mean implementing get methods for primitives eg instead of getRecordSize you could use: 我的意思是为原语实现get方法,例如,可以使用getRecordSize代替:

  private int getShort(byte[] input, int index)
  {
        byte[] shortBytes= Arrays.copyOfRange(input,index,2);
        return ByteBuffer.wrap(shortBytes).getShort();
  }

So whenever you have to read a short you can use this function and just have to toss in the index. 因此,每当您需要阅读简短内容时,都可以使用此功能,而只需输入索引。

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

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