JNI GetByteArrayElements()错误

时间:2016-08-05 09:39:51

标签: java c java-native-interface c-strings

我是JNI的新人,所以我对JNI和英语都不熟悉。

我的JNI项目是一个简单的文件读写。使用Java将文件读取并将字节数组传递给C API,然后使用C。

将其写入文件

我的源代码:

Java代码是:

public class FileIO {
   static {
      System.loadLibrary("FileIO");         
   }

   private native void writeFile(byte[] msg);

   public static void main(String[] args) throws IOException { 

      byte[] array = Files.readAllBytes(new File("PtFBWCTn.mp3").toPath());

      // System.out.println(array.length);
      new FileIO(). writeFile(array); 
   }
}

C代码:

#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "HelloJNI.h"

JNIEXPORT void JNICALL Java_FileIO_ writeFile (JNIEnv *env, jobject job, jbyteArray array ){

    jsize num_bytes = (*env)->GetArrayLength(env, array);
    printf("Byte length : %d\n" , num_bytes);

    unsigned char * buffer;
    jbyte  *lib ;
    lib =(jbyte *) malloc( ( num_bytes +1 ) * sizeof(jbyte));

    (*env)->GetByteArrayRegion(env , array, 0 , num_bytes , lib);
    // lib = (*env)->GetByteArrayElements(env , array, 0);
    buffer =(char *) lib ;
    FILE *fp;
    fp=fopen("test.mp3", "wb");
    printf("size : %d , length : %d  ,contant : %s\n" ,(int)sizeof(buffer), (int)strlen(buffer) ,  buffer );

    fwrite(buffer, sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp);
    return;
}

我在传递(.zip.mp3.mp4.jpg.png)文件字节数组时出现问题。我尝试了一些文本文件格式,如.txt.java.c文件正在创建我所期望的。

是什么原因?

我试过(用Java读取我的java文件(FileIO.java),输出是):

Byte length : 238653
size : 8 , length : 4  ,contant : import java.nio.file.Files;
import java.io.File;

public class FileIO {
   static {
      System.loadLibrary("FileIO");         
   }

   private native void writeFile(byte[] msg);

   public static void main(String[] args) throws IOException { 

      byte[] array = Files.readAllBytes(new File("PtFBWCTn.mp3").toPath());

      // System.out.println(array.length);
      new FileIO(). writeFile(array); 
   }
}

我试过(一些test.png和输出):

Byte length : 381729
size : 8 , length : 8  ,contant : ?PNG

GetByteArrayElements()在读取媒体和其他某种格式时仅返回8个字节。但是在文本文件的情况下,它返回正确的字节数。 请说明为什么长度为'png&#39;和其他一些格式长度不等于字节长度。并提供如何解决这个问题的方法。

3 个答案:

答案 0 :(得分:2)

{"1", "2", "." "800"}

答案 1 :(得分:1)

正如您所见,the man说:

  

<强>描述

     

strlen()函数计算指向的字符串的长度          by s,不包括终止空字节('\ 0')。

     

返回值

     

strlen()函数返回字符串中的字符数          s指出。

这意味着您无法打开纯二进制文件并假装使用该函数拥有内容的长度,因为它会在第一个null terminator处停止计算字符数。换句话说,它会在设置为0的第一个字节处停止计数。

显然它适用于编码的文本文件,以确保单词之间没有null terminator

第二个错误是(int)sizeof(buffer)它返回类型对象表示的字节大小,在您的情况下是pointerunsigned char。在您的平台上(64位..)指针长度为8个字节。

附注:您可以避免使用size_t格式说明符来转换返回"%zu"类型的函数的返回值。

printf("size : %zu , length : %zu  ,contant : %s\n" , sizeof(buffer), strlen(buffer) ,  buffer );

修改

您无法以这种方式检索读取字节的大小。

没有可以检索动态分配数组大小的标准函数。

您必须编写自己的代码。例如,对于png文件,您可以通过文件头检索长度。看看PNG specifications

答案 2 :(得分:1)

首先,您不应为目标缓冲区分配额外字节:

lib =(jbyte *) malloc( ( num_bytes +1 ) * sizeof(jbyte));

没必要。您也可以省略sizeof(jbyte),因为它总是1

lib = (jbyte *) malloc(num_bytes);

然后:

printf("size : %d , length : %d  ,contant : %s\n" ,(int)sizeof(buffer), (int)strlen(buffer) ,  buffer );

(int)sizeof(buffer)是指针变量的大小,而不是已寻址数据的大小,程序公平地告诉您指针是8字节长度的对象(您在64位主机上)。接下来,(int)strlen(buffer)不返回指向数据的实际大小,而是返回数据中第一个零('\0')字节之前的字节数。

由于此strlen()结果与从文本文件中读取的数据长度相匹配 - 它们几乎总是不包含零字节。二进制文件,如PNG,MP3等,经常包含零字节,实际长度与strlen()结果不匹配。

最重要的是:唯一真正的数据长度 - 是GetArrayLength()的结果。

修改

fwrite()的实际参数不正常:

fwrite(buffer, sizeof(buffer[0]), sizeof(buffer)/sizeof(buffer[0]), fp);

sizeof(buffer)/sizeof(buffer[0]8/1相同,因为buffer是8字节长度指针而buffer[0]unsigned char,即一个字节长度的实体。你应该像这样重写它:

fwrite(buffer, 1, num_bytes, fp);

并且没有标准功能可以帮助您打印包括零的所有数据。我猜你应该手动遍历每个字节,格式化和打印。