简体   繁体   English

JNI GetByteArrayElements()错误

[英]JNI GetByteArrayElements () Error

I'm new in JNI so I'm not familiar in JNI and also English. 我是JNI的新手,所以我对JNI和英语都不熟悉。

My JNI project is a simple File reading and writing. 我的JNI项目是一个简单的文件读写。 File reading in Java and passing the byte array to C API the write it into file using C. 使用Java读取文件并将字节数组传递给C API,使用C将其写入文件。

My source code: 我的源代码:

Java code is : 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 code : 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;
}

I got problem while I am passing ( .zip , .mp3 , .mp4 , .jpg and .png ) file byte array. 当我传递( .zip.mp3.mp4.jpg.png )文件字节数组时,我遇到了问题。 I try some text file formats like .txt , .java , .c files are create what I expect. 我尝试一些文本文件格式,如.txt.java.c文件创建我期望的。

What is the reason? 是什么原因?

I tried (reading my java file(FileIO.java) in Java and the output is): 我试过(用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); 
   }
}

And I tried (some test.png and the output is): 我试过(一些test.png和输出):

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

GetByteArrayElements () returns only 8 bytes while reading media and other some format. GetByteArrayElements()在读取媒体和其他某些格式时仅返回8个字节。 But in case of text file it returns correct amount of bytes. 但是在文本文件的情况下,它返回正确的字节数。 Please provide the reason for why the length of the 'png' and other some format length is not equal to Byte length. 请说明为什么'png'的长度和其他某些格式长度不等于字节长度的原因。 And provide way to how to solve this problem. 并提供如何解决这个问题的方法。

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

As you can see the man says: 你可以看到那个男人说:

DESCRIPTION 描述

The strlen() function calculates the length of the string pointed to by s, excluding the terminating null byte ('\\0'). strlen()函数计算s指向的字符串的长度,不包括终止空字节('\\ 0')。

RETURN VALUE 返回值

The strlen() function returns the number of characters in the string pointed to by s. strlen()函数返回s指向的字符串中的字符数。

That means that you cannot open a pure binary files and pretend to have the length of the content using that function, because of it stops counting chars at the first null terminator . 这意味着您无法打开纯二进制文件并伪装使用该函数的内容长度,因为它会停止计算第一个null terminator字符。 In other words it stops counting at the first byte set to 0 . 换句话说,它会在设置为0的第一个字节处停止计数。

Obviously it works with text file that are encoded to ensure no null terminator between words. 显然它适用于编码的文本文件,以确保单词之间没有null terminator

The second error is (int)sizeof(buffer) it returns size in bytes of the object representation of type, that in your case is a pointer to unsigned char . 第二个错误是(int)sizeof(buffer)它返回类型的对象表示的字节大小,在您的情况下是pointer unsigned charpointer On your platform (64 bits..) pointers are 8 bytes long. 在您的平台上(64位..)指针长度为8个字节。

Side note: you can avoid to cast return value of function that return size_t type using "%zu" format specifier. 注意:您可以避免使用"%zu"格式说明符来转换返回size_t类型的函数的返回值。

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

EDIT 编辑

You can't retrieve the size of read bytes that way. 您无法以这种方式检索读取字节的大小。

There isn't a standard function that can retrieve size of a dynamically allocated array. 没有标准函数可以检索动态分配的数组的大小。

You must write your own code. 你必须编写自己的代码。 For example for png file you can retrieve the length through the header of file. 例如,对于png文件,您可以通过文件头检索长度。 Take a look at PNG specifications 看看PNG规格

First of all you shouldn't allocate extra byte for destination buffer: 首先,您不应为目标缓冲区分配额外字节:

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

it is unnecessary. 这是不必要的。 Also you may omit sizeof(jbyte) since it is always 1 : 你也可以省略sizeof(jbyte)因为它总是1

lib = (jbyte *) malloc(num_bytes);

Then: 然后:

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

(int)sizeof(buffer) is a size of a pointer variable, not a size of addressed data, and program fairly tells you that pointer is 8-byte length object (you are on 64-bit host). (int)sizeof(buffer)是指针变量的大小,而不是寻址数据的大小,程序公平地告诉你指针是8字节长度的对象(你在64位主机上)。 Next, (int)strlen(buffer) doesn't return actual size of pointed data, instead it returns the number of bytes that precede the first zero ( '\\0' ) byte in your data. 接下来, (int)strlen(buffer)不返回指向数据的实际大小,而是返回数据中第一个零( '\\0' )字节之前的字节数。

And because of this strlen() result matches with length of data that were read from text files - they almost always don't contain zero bytes. 因为这个strlen()结果与从文本文件中读取的数据长度匹配 - 它们几乎总是不包含零字节。 And binary files, like PNG, MP3, so on contain zero bytes frequently, and actual length doesn't match with strlen() result. 二进制文件,如PNG,MP3等,经常包含零字节,实际长度与strlen()结果不匹配。

To top it off: the only true data length - is the result of GetArrayLength() . 最重要的是:唯一真正的数据长度 - 是GetArrayLength()的结果。

EDIT 编辑

Actual arguments for fwrite() are not OK: fwrite()实际参数不正常:

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

sizeof(buffer)/sizeof(buffer[0] is the same as 8/1 , since buffer is a 8-byte length pointer and buffer[0] is unsigned char ie one byte length entity. You should rewrite it like this: sizeof(buffer)/sizeof(buffer[0]8/1相同,因为buffer是一个8字节长度的指针, buffer[0]unsigned char即一个字节长度的实体。你应该像这样重写它:

fwrite(buffer, 1, num_bytes, fp);

And there is no standard function that can help you to print all data including zeros. 并且没有标准功能可以帮助您打印包括零的所有数据。 I guess you should manually loop over each byte, format and print. 我想你应该手动循环每个字节,格式化和打印。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM