JNI GetByteArrayElements () ошибка
Я новичок в 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 : %dn" , 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 : %sn" ,(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-файл (FileIO.java) в 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);
}
}
И я попробовал (какой-то тест.png и вывод):
Byte length : 381729
size : 8 , length : 8 ,contant : ?PNG
GetByteArrayElements () возвращает только 8 байт при чтении носителя и другого некоторого формата. Но в случае текстового файла он возвращает правильное количество байт. Пожалуйста, укажите причину, по которой длина " png " и других некоторых форматов длины не равна длине байта. И обеспечить способ, как решить эту проблему.
3 ответа:
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);
Прежде всего, вы не должны выделять дополнительный байт для буфера назначения:
В этом нет необходимости. Также вы можете опустить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()
.EDIT
Фактические аргументы для
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);
И нет никакой стандартной функции, которая может помочь вам распечатать все данные, включая нули. Я думаю, что вы должны вручную перебирать каждый байт, форматировать и печатать.
Как вы можете видеть человек говорит:
Описание
Функция strlen() вычисляет длину строки, на которую указывает по s, исключая завершающий нулевой байт ('\0').
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
Функция strlen () возвращает количество символов в строке на что указывает С.
Это означает, что вы не можете открыть чистый двоичный файл и притвориться, что у него есть длина содержания, использующего эту функцию, из-за нее прекращается подсчет символов при первом
Очевидно, что он работает с текстовым файлом, который закодирован для обеспечения отсутствияnull terminator
. Другими словами, он прекращает отсчет при первом байте, установленном в0
.null terminator
между словами.Вторая ошибка -
(int)sizeof(buffer)
она возвращает размер в байтах объектного представления типа, который в вашем случае являетсяpointer
кunsigned char
. На вашей платформе (64 бит..) указатели имеют длину 8 байт.Примечание сбоку: вы можете избежать, чтобы бросить возвращает значение функции, возвращающей тип
size_t
с помощью спецификатора формата"%zu"
.printf("size : %zu , length : %zu ,contant : %s\n" , sizeof(buffer), strlen(buffer) , buffer );
EDIT
Вы не можете получить размер прочитанных байтов таким образом.
Не существует стандартной функции, которая может получить размер динамически выделенного массива.
Вы должны написать свой собственный код. Например, для файла
png
вы можете получить длину через заголовок файла. Взгляните на PNG спецификации