Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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

My JNI project is a simple File reading and writing. File reading in Java and passing the byte array to C API the write it into file using C.

My source code:

Java code is :

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 :

#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. I try some text file formats like .txt, .java , .c files are create what I expect.

What is the reason?

I tried (reading my java file(FileIO.java) in Java and the output is):

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

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

GetByteArrayElements () returns only 8 bytes while reading media and other some format. 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. And provide way to how to solve this problem.

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); ` char buffer[num_bytes];` - VLA is a bad approach. Try to open a large file, say 1 GB or more. VLA have unpredictable impact on stack so you should avoid them. – Sergio Aug 5, 2016 at 11:07 I just want to add a note that primitiveType array[arrayLength]; is not a bad approach if arrayLength is just a small value with respect to the array type and is a constant expression or a macro. – 0xdeadbeef Apr 7 at 5:26

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:

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

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. And binary files, like PNG, MP3, so on contain zero bytes frequently, and actual length doesn't match with strlen() result.

To top it off: the only true data length - is the result of GetArrayLength().

Actual arguments for fwrite() are not OK:

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 i.e. one byte length entity. You should rewrite it like this:

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.

strlen() it's not a problem. Because output file size also has only 8 bytes. Then How to print all the binary bytes including all zero bytes. – Muthu GM Aug 5, 2016 at 10:11 Your edit is also same old code. I tried your edit it is also same problem. What is the problem is in my idea binary file have lot of null char, char * buffer wrting is stoped in the first null char that is the reason How to I solve. – Muthu GM Aug 5, 2016 at 10:30 @MuthuGM Are you sure that fwrite(buffer, 1, num_bytes, fp); gives the same result as before? – Sergio Aug 5, 2016 at 10:33

The strlen() function calculates the length of the string pointed to by s, excluding the terminating null byte ('\0').

RETURN VALUE

The strlen() function returns the number of characters in the string pointed to by 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. In other words it stops counting at the first byte set to 0.

Obviously it works with text file that are encoded to ensure no null terminator between words.

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. On your platform (64 bits..) pointers are 8 bytes long.

Side note: you can avoid to cast return value of function that return size_t type using "%zu" format specifier.

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

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. Take a look at PNG specifications

@MuthuGM See last lines of my answer. In your case sizeof return the size of unsigned char * – LPs Aug 5, 2016 at 10:10 Yeah! I know sizeof will return the size of data types like (char, int, char *). But which data type I use in this case? Because binary contains lot of null char. – Muthu GM Aug 5, 2016 at 10:14 You can't do that in 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. – LPs Aug 5, 2016 at 10:19

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.