使用Inputstream将二进制数据转换为long [],同时保持原始顺序

时间:2015-05-10 11:45:31

标签: java android performance inputstream

问题描述

我有一个2mb的文件,其中只包含二进制数据。我只需要将此文件转换为long[],同时保持数据在该文件中的顺序。由于在Android上读取文件,因此我只能以InputStream的形式访问该文件。我迫切想要完成的最后一件事(以及我将数据放入压缩二进制数据格式的原因)是尽可能快地完成。

Android的工作代码

由于我无法在android上获得File并且只能使用resource并将该文件表示为InputStream,我必须为我的桌面编写使用InputStream而不是文件。在我的移动旗舰手机上,使用此代码平均花费了61毫秒:

DataInputStream dis = new DataInputStream(context.getResources().openRawResource(fileID));
int bytesOfBinaryFile = dis.available();
byte[] bytes = new byte[bytesOfBinaryFile];
dis.readFully(bytes);
int longCount = bytesOfBinaryFile / 8;
long[] array = new long[longCount];
bytesToLongArray(bytes, array);

bytesToLongArray(bytes, array)

private void bytesToLongArray(byte[] bytes, long[] longs) {
    int numberOfLongs = longs.length;
    int head = 0;
    long l;
    for (int i = 0; i < numberOfLongs; i++) {
        l = ((bytes[head] & 0xFFL) << 56) |
                ((bytes[head + 1] & 0xFFL) << 48) |
                ((bytes[head + 2] & 0xFFL) << 40) |
                ((bytes[head + 3] & 0xFFL) << 32) |
                ((bytes[head + 4] & 0xFFL) << 24) |
                ((bytes[head + 5] & 0xFFL) << 16) |
                ((bytes[head + 6] & 0xFFL) <<  8) |
                ((bytes[head + 7] & 0xFFL) <<  0) ;
        longs[i] = l;
        head += 8;
    }
}

桌面

的类似工作代码

仅供参考和比较,我包含此代码。我把它在我的桌面上运行得非常快(只需要大约3.5毫秒)就可以将2mb文件加载到long[]

String fileName = "example";
FileInputStream fip = new FileInputStream(fileName);
FileChannel fc = fip.getChannel();
double bytesOfBinaryFile = fc.size();
int longCount = (int) bytesOfBinaryFile / 8;
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_ONLY,
        0L, fc.size());
LongBuffer lb = mbb.asLongBuffer(); 
long[] array = long[longCount];
lb.get(array);

问题

我想知道是否有人知道更快的方式或方法来改进我目前的方法。我希望仍有改进性能的空间。

2 个答案:

答案 0 :(得分:1)

这可能就是你要找的东西:

List<Asset> pesonsList= new ArrayList<>();
for (Room room : rooms) 
     room.getPersonsList().stream()
                       .filter(person -> person.isTall())
                       .forEach(person -> {
                               doSomething(person);
                               pesonsList.add(person);
                       });

http://developer.android.com/reference/java/nio/ByteBuffer.html#asLongBuffer%28%29

答案 1 :(得分:1)

也许这个循环会更快:

for(int i=0; i<bytes.length; ++i) {
  longs[i >> 3] |= (bytes[i] & 0xFFL) <<  ((7-(i & 3))<<3);
}

或者如果你想使用不同的字节顺序 - 第一个字节是长的最低 - 而不是这个(减去一个减法操作):

for(int i=0;i<bytes.length;++i) {
  longs[i >> 3] |= (bytes[i] & 0xFFL) <<  ((i & 3)<<3);
}

但请注意,bytes.length必须可被8整除,否则你需要在longs数组中加一个长的。

此外,数组中的longs必须初始化为零。但据我所知,当你分配数组时它会自动完成。