JNI GetByteArrayElements () 错误

JNI GetByteArrayElements () Error

我是 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() returns 读取媒体和其他一些格式时只有 8 个字节。但在文本文件的情况下,它 returns 正确的字节数。 请说明为什么'png'和其他一些格式的长度不等于字节长度的原因。并提供解决这个问题的方法。

如你所见the man 说:

DESCRIPTION

The strlen() function calculates the length of the string pointed to by s, excluding the terminating null byte ('[=20=]').

RETURN VALUE

The strlen() function returns the number of characters in the string pointed to by s.

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

的第一个字节停止计数

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

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

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

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

编辑

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

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

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

首先你不应该为目标缓冲区分配额外的字节:

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) 不是 return 指向数据的实际大小,而是 return 数据中第一个零 ('[=19=]') 字节之前的字节数。

因此 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);

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

    jsize num_bytes = (*env)->GetArrayLength(env, array);
    char * buffer;

    buffer = (char *) malloc (num_bytes);

    jbyte  *lib = (*env)->GetByteArrayElements(env , array, 0);

    memcpy ( buffer , lib , num_bytes ) ;

    FILE *fp;
    fp=fopen("test.png", "wb");
    fwrite(buffer, sizeof(char) , num_bytes , fp);