java byte 转 c,如何在JNI中将Java字节数组的内容转换为C字符串?

Update:

Error: jbyte* elements = (*env)->GetByteArrayElements(env, array, NULL); returns only 8 bytes. Provide any alternative to way to retrieve byte form jbytearray.

I'm new in JNI so I'm not familiar in JNI and also English.

Now I try the simple JNI program on File reading in Java and write it into file using C.

File reading java code:

public class FileIO {

static {

System.loadLibrary("io");

}

private native void writeToFile(byte[] msg);

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

FileInputStream fileInputStream=null;

File file = new File("version1-1.png");

byte[] bFile = new byte[(int) file.length()];

try {

//convert file into array of bytes

fileInputStream = new FileInputStream(file);

fileInputStream.read(bFile);

fileInputStream.close();

System.out.println("Done");

} catch(Exception e){

e.printStackTrace();

}

new FileIO().writeToFile(bFile);

}

}

File write C code:

#include

#include

#include

#include "FileIO.h"

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

char * buf ;

// here what i do ??? :(

FILE *file = fopen("test123.png", "w");

int results = fputs(buf, file);

if (results == EOF) {

//Failed to write do error code here.

}

fclose(file);

}

I have tried many solutions (below link) but no luck in writing it to the file. Please provide the correct solution and best JNI tutorial site.

Already tried solution: (But not success)

int len = (*env)->GetArrayLength (env , array );

printf(" Length of the bytearray %d\n", len );

unsigned char * string ;

string = (char *)malloc((len + 1) * sizeof(char)) ;

jbyte* b = (*env)->GetByteArrayElements(env, array, &isCopy);

After GetByteArrayElements jbyte length should be 8 but the GetArrayLength returns bytearray length is 50,335.

What i try :

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

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

char *buffer = malloc(num_bytes + 1);

printf("Number of jByte element : %d\n", (int) num_bytes);

if (!buffer)

printf("Buff Fail\n");

jbyte* elements = (*env)->GetByteArrayElements(env, array, NULL);

if (!elements)

printf("Element Fail\n");

printf ("Number of Byte elements : %d\n", (int) strlen (elements));

memcpy(buffer, elements, num_bytes);

buffer[num_bytes] = 0;

printf("Number of buffer elements : %d\n", (int) strlen(elements));

(*env)->ReleaseByteArrayElements(env, array, elements, JNI_ABORT);

FILE *fp;

fp = fopen( "file.txt" , "w" );

fwrite(buffer , 1 , sizeof(buffer) , fp );

fclose(fp);

return;

}

AND the Output:

Done

Number of jByte element : 50335

Number of Byte elements : 8

Number of buffer elements : 8

解决方案

As @Olaf observed, pointers and arrays are altogether different kinds of objects. There is no meaningful way to convert one to another. The first step, therefore, is to better characterize what you actually mean.

Since your ultimate objective appears to be to write the bytes of the Java array to a file via fputs(), it seems that what you want to do is to create a C string whose contents are the same as the Java byte array's. This is exactly what Olaf's proposed dupe, Converting jbyteArray to a character array, and then printing to console, requests, and what the accepted answer purports to provide. You claim, however, that you already tried that solution and it didn't work. You don't describe the nature of the failure, but I can believe that it does fail, because the solution in the accepted answer is a bit buggy. In what follows, I'll refer to that answer as "the historic answer".

The historic answer is quite correct on several points. In particular, a C string must be null-terminated, and the contents of a Java byte array are not terminated, unless accidentally. Also, the jbytearray pointer is not a pointer directly to the data, so you need to use appropriate JNI functions to get the data themselves. You'll need to create a new buffer large enough for the byte array's contents plus the terminator, copy the bytes into it, and add the terminator.

For example:

// determine the needed length and allocate a buffer for it

jsize num_bytes = GetArrayLength(env, array);

char *buffer = malloc(num_bytes + 1);

if (!buffer) {

// handle allocation failure ...

}

// obtain the array elements

jbyte* elements = GetByteArrayElements(env, array, NULL);

if (!elements) {

// handle JNI error ...

}

// copy the array elements into the buffer, and append a terminator

memcpy(buffer, elements, num_bytes);

buffer[num_bytes] = 0;

// Do not forget to release the element array provided by JNI:

ReleaseByteArrayElements(env, array, elements, JNI_ABORT);

After that, you have in the space pointed to by buffer a null-terminated copy of the contents of the byte array, which you can, for example, pass to fputs():

int result = fputs(buffer, file);

Also, once you successfully allocate the buffer, you must be certain to free it before returning from the function, including via any error-handling return path:

free(buffer);

The main problem I see with the historic answer is that it suggests using strlen() to compute the length of the array data so as to be able to allocate a sufficiently large temporary buffer. But that could work only if the byte array were already null terminated, in which case it wouldn't be necessary in the first place.

Update

The above answers the question as posed -- how to convert the data to a C string. Note, however, that the question itself is premised on the supposition that converting the data to a C string and outputting them via fputs() is an appropriate mechanism in the first place. As @Michael observed, that is not the case if the data contain null bytes, as may be difficult to rule out if they originally come from a binary file.

If the overall objective is simply to write the bytes to a file, then first converting them to a C string is pointless. There are alternative mechanisms for outputting the data without first performing such a conversion. If the data can be relied upon not to contain internal null bytes, then you can use fprintf() to write them:

fprintf("%*s", (int) num_bytes, (char *) elements);

On the other hand, if the data may contain nulls then you should use an appropriate low-level output function. That might look like this:

#include

#include

#include "FileIO.h"

JNIEXPORT void JNICALL Java_FileIO_writeToFile(JNIEnv *env, jobject job,

jbyteArray array) {

FILE *fp = fopen( "file.txt" , "w" );

if (!fp) {

// handle failure to open the file ...

}

// determine the needed length and allocate a buffer for it

jsize num_bytes = GetArrayLength(env, array);

// obtain the array elements

jbyte* elements = GetByteArrayElements(env, array, NULL);

if (!elements) {

// handle JNI error ...

}

// output the data

if (fwrite(elements, 1, num_bytes, fp) != num_bytes) {

// handle I/O error ...

}

// Do not forget to release the element array provided by JNI:

ReleaseByteArrayElements(env, array, elements, JNI_ABORT);

fclose(fp);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值