将压缩的 FlatBuffer 写入文件并从文件中读回的问题

Issues with writing compressed FlatBuffer to file and reading back from file

我已经成功地将 FlatBuffer 数据写入文件,并且可以从文件中读回。但是现在我试图在写入文件之前压缩 Flatbuffer 数据。当我尝试从文件中读回压缩数据并解压缩时,它不起作用。

任何帮助将不胜感激,因为我是平面缓冲区和 java 压缩的新手。

** FlatBuffer 架构**

table employees {
   persons:[Person];
}
 
table Person {
  fname:string;
  mname:string;
  lname:string;
  age:short;
}
  

MainActivity.java

package com.irteqa.flatbufferdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

import com.google.flatbuffers.FlatBufferBuilder;

import fb.Person;
import fb.employees;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;


public class MainActivity extends AppCompatActivity {

    private static final String TAG = "FlatBufferDemo";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        createBinaryData();
    }

    public void createBinaryData() {

        List<PersonEntity> personEntityList = new ArrayList<>();

        for (int i = 0; i < 1; i++) {
            PersonEntity personEntity = new PersonEntity("Stephen" + (i + 1), "Wardell", "Curry", (short) (i + 1));
            personEntityList.add(personEntity);
        }

        writeBinaryData(personEntityList);

        // ************************************************************************
        // Reading Data
        // ************************************************************************
        String filepath = getFilesDir() + "/person.dat";
        ByteBuffer buffer = null;
        // ByteBuffer buffer = readByteBufferfromFile(filepath);
        try {
            byte[] bytesComp = readBytesFromFile(filepath);
            buffer = CompressionUtil.decompress(bytesComp);

        } catch (IOException e) {
            e.printStackTrace();
        }

        // Get access to the root:
        employees all_employees = employees.getRootAsemployees(buffer);

        // Note: We did not set the `mana` field explicitly, so we get back the default value.
        Log.d(TAG, "reading ByteBuffer: ");
        for (int i = 0; i < all_employees.personsVector().length(); i++) {
            Person person = all_employees.persons(i);
            Log.d(TAG, person.fname() + " " + person.mname() + " " + person.lname() + " " + person.age());
        }

    }

    private ByteBuffer readByteBufferfromFile(String filepath) {
        ByteBuffer buffer = null;
        try (RandomAccessFile aFile = new RandomAccessFile(filepath, "r");
             FileChannel inChannel = aFile.getChannel();) {

            long fileSize = inChannel.size();

            //Create buffer of the file size
            buffer = ByteBuffer.allocate((int) fileSize);
            inChannel.read(buffer);
            buffer.flip();

        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer;

    }

    private void writeBinaryData(List<PersonEntity> personEntityList) {

        Log.d(TAG, "Writing ByteBuffer: ");

        FlatBufferBuilder builder = new FlatBufferBuilder(0);

        int[] persons = new int[personEntityList.size()];

        for (int i = 0; i < personEntityList.size(); i++) {

            PersonEntity ent = personEntityList.get(i);

            int fnameOffset = builder.createString(ent.fname);
            int mnameOffset = builder.createString(ent.mname);
            int lnameOffset = builder.createString(ent.lname);
            short age = ent.age;

            persons[i] = Person.createPerson(builder
                    , fnameOffset
                    , mnameOffset
                    , lnameOffset
                    , age);
        }

        int personsVector = employees.createPersonsVector(builder, persons);
        employees.startemployees(builder);
        employees.addPersons(builder, personsVector);
        int orc = employees.endemployees(builder);
        builder.finish(orc);


        ByteBuffer buf = builder.dataBuffer();
        String filepath = getFilesDir() + "/person.dat";

        // writeByteBuffertoFile(buf, filepath); // writing ByteBuffer wihtout compression

        // compress and write to file
        try {
            byte[] bytesCompressed = CompressionUtil.compress(buf);
            writeBytestoFile(bytesCompressed, filepath);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private void writeBytestoFile(byte[] bytesCompressed, String outputFile) {
        try (FileOutputStream outputStream = new FileOutputStream(outputFile)) {
            outputStream.write(bytesCompressed);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void writeByteBuffertoFile(ByteBuffer buf, String filepath) {

        FileChannel fc = null;
        try {
            File file = new File(filepath);
            fc = new FileOutputStream(file).getChannel();

            fc.write(buf);
            fc.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static byte[] readBytesFromFile(String file) throws IOException {

        File f = new File(file);

        // work only for 2GB file, because array index can only upto Integer.MAX

        byte[] buffer = new byte[(int) f.length()];

        FileInputStream is = new FileInputStream(file);

        is.read(buffer);

        is.close();

        return buffer;

    }
}

** CompressionUtil **

package com.irteqa.flatbufferdemo;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

public class CompressionUtil {

    public static byte[] compress(ByteBuffer buffer) throws IOException {

        byte[] bytes = buffer.array();

        ByteArrayOutputStream os = new ByteArrayOutputStream(bytes.length);
        GZIPOutputStream gos = new GZIPOutputStream(os);
        gos.write(bytes);
        gos.close();
        byte[] compressed = os.toByteArray();
        os.close();
        return compressed;
    }

    public static ByteBuffer decompress(byte[] compressed) throws IOException {
        final int BUFFER_SIZE = 1024;
        ByteArrayInputStream is = new ByteArrayInputStream(compressed);
        GZIPInputStream gis = new GZIPInputStream(is, BUFFER_SIZE);

        byte[] data = new byte[BUFFER_SIZE];
        ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE*2);
        int bytesRead;
        while ((bytesRead = gis.read(data)) != -1) {
            buffer.put(data, 0 , bytesRead);
        }
        gis.close();
        is.close();
        return buffer;
    }
}

我收到以下错误:

2022-05-24 10:24:56.238 4231-4231/com.irteqa.flatbufferdemo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.irteqa.flatbufferdemo, PID: 4231
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.irteqa.flatbufferdemo/com.irteqa.flatbufferdemo.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'int fb.Person$Vector.length()' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2416)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
        at android.app.ActivityThread.-wrap11(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:148)
        at android.app.ActivityThread.main(ActivityThread.java:5417)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int fb.Person$Vector.length()' on a null object reference
        at com.irteqa.flatbufferdemo.MainActivity.createBinaryData(MainActivity.java:68)
        at com.irteqa.flatbufferdemo.MainActivity.onCreate(MainActivity.java:35)
        at android.app.Activity.performCreate(Activity.java:6237)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476) 
        at android.app.ActivityThread.-wrap11(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:148) 
        at android.app.ActivityThread.main(ActivityThread.java:5417) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616) 
2022-05-24 10:29:56.401 4231-4231/com.irteqa.flatbufferdemo I/Process: Sending signal. PID: 4231 SIG: 9

看起来你正在将 ByteBuffer 压缩到平面缓冲区,而不是从 0 开始。最好序列化你从 builder.sizedByteArray().