将数据从JNI函数撤回到Android应用程序代码

时间:2018-01-04 13:34:43

标签: java android c android-ndk

我正在开发一个Android应用程序,我正在使用一个本机C库。该库用于文件解压缩。

本机方法的定义如下:

public static native Long decompress(ByteBuffer src, ByteBuffer dst);

我使用此功能的应用程序代码如下:

try {
            File inFile = new File(Environment.getExternalStorageDirectory().getPath() +"/1"); // source file

            ByteBuffer buf = ByteBuffer.allocateDirect((int)inFile.length());

            ByteBuffer buf_out = ByteBuffer.allocateDirect((int)inFile.length()*20);

            InputStream is = new FileInputStream(inFile);

            int b;

            while ((b=is.read())!=-1) {
                buf.put((byte)b);
            }
            Log.d("nims","source buffer zie"+buf.position());
            File file = new File(Environment.getExternalStorageDirectory().getPath() +"/2");

            // append or overwrite the file
            boolean append = false;

            FileChannel channel = new FileOutputStream(file, append).getChannel();

            Long t = decompress(buf,buf_out); // t is some XYZ number

            Log.d("nims","dest buffer zie"+buf_out.position()); // buf_out.position() returns 0
            buf_out.flip();

            // Writes a sequence of bytes to this channel from the given buffer.
            channel.write(buf_out);

            // close the channel
            channel.close();

        }
        catch (IOException e) {
            System.out.println("I/O Error: " + e.getMessage());
        }

JNI代码

JNIEXPORT jlong JNICALL 

    Java_com_company_appName_MainActivity_decompress(JNIEnv* env, jclass cls, jobject src, jobject dst) {

        uint8_t* src_buffer = (*env)->GetDirectBufferAddress(env,src);
        const size_t src_size = (*env)->GetDirectBufferCapacity(env, src);

        uint8_t* dst_buffer = (*env)->GetDirectBufferAddress(env,dst);

        size_t dst_size = (*env)->GetDirectBufferCapacity(env, dst);
        jlong test = _decode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL);

        return test;
    }

目标缓冲区不包含任何数据。

我有以下问题:

  1. 如何将目标字节缓冲区从JNI代码读回应用程序代码?
  2. 如何将目标bytebuffer数据写入文件?
  3. 我很感激有关这个主题的任何建议和想法。

    编辑1:

    size_t test = lzfse_decode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL);
    
        ALOG("Size of test %d.",test); // output is 319488
        ALOG("Size of test after casting  %ld.",(jlong)test); // output is -125648933
    
    
        //New code from stack overflow
        jclass cls2 = (*env)->GetObjectClass(env, dst);
        jmethodID limitId = (*env)->GetMethodID(env, cls2, "limit", "(I)Ljava/nio/Buffer;");
        (*env)->CallObjectMethod(env, dst, limitId,(jlong) test);
        jmethodID positionId = (*env)->GetMethodID(env, cls2, "position", "(I)Ljava/nio/Buffer;");
        (*env)->CallObjectMethod(env, dst, positionId, 0);
    

    编辑2:

    size_t test = lzfse_decode_buffer(dst_buffer, dst_size, src_buffer, src_size, NULL);
         ALOG("Size of test %d.",test); // output is 319488
        ALOG("Size of test after casting  %d.",(jint)test); // output is 319488
        //New code from stack overflow
        jclass cls2 = (*env)->GetObjectClass(env, dst);
        jmethodID limitId = (*env)->GetMethodID(env, cls2, "limit", "(I)Ljava/nio/Buffer;");
        (*env)->CallObjectMethod(env, dst, limitId,(jint) test);
        jmethodID positionId = (*env)->GetMethodID(env, cls2, "position", "(I)Ljava/nio/Buffer;");
        (*env)->CallObjectMethod(env, dst, positionId, 0);
    

1 个答案:

答案 0 :(得分:3)

当您在C中写入DirectByteBuffer时,这不会改变大小(limit)和position   dst 缓冲区。你必须自己设置。您可以使用本机代码执行此操作:

jclass cls = (*env)->GetObjectClass(env, dst);
jmethodID limitId = (*env)->GetMethodID(env, cls, "limit", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, limitId, actual_size);
jmethodID positionId = (*env)->GetMethodID(env, cls, "position", "(I)Ljava/nio/Buffer;");
(*env)->CallObjectMethod(env, dst, positionId, 0);

这假设您可以从_decode_buffer()函数中检索写入 dst 缓冲区的实际字节数。

你不需要翻转()