-1

I have an image in a form that jbytearray in c++. I need to write it to txt file. I did many solutions on stackoverflow but none of them worked for me.

when I cast jbyteArray into char *, it is successfully write it, but i need to write it as a jbyteArray, because I need to compare jbyteArray's content in java and c++. I write jbyteArrays which comes from c++ to txt file and also I need to jbytesArray in c++ part. Therefore I need to write jbyteArray as jbyteArray not as char *

Here is what i tried;

Trial 1

std::ofstream("myfile.bin", std::ios::binary).write(data, 100);

Problem with Trial 1

Argument of type "jbyteArray" is incompatible with parameter of type "const char *"

Thank You very much.

ozer
  • 241
  • 2
  • 12
  • 1
    All of these solutions could be correct (except maybe the third, that's a bit strange). If you want some help you really are going to have to say what went wrong when you tried them. I think you should also make clear precisely what you mean by a `jbytearray`. – john Dec 09 '20 at 16:27
  • Short answer: `jbytearray` is a Java object. You need to call `GetByteArrayElements` (and then the release function). – Artefacto Dec 09 '20 at 16:30
  • @john I edited question – ozer Dec 09 '20 at 16:36
  • @Artefacto What do you mean I can not understand ? Before I pass the value of jbytearray I need to see its content so i need to write it to txt file. – ozer Dec 09 '20 at 16:37
  • @ozer yes, that's basically it. See https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp17382 You'll get a jbyte* (a char*). – Artefacto Dec 09 '20 at 16:45
  • @ozer The first problem can be solved by doing either of the things in the error message `Consider using fopen_s instead` or `To disable deprecation, use _CRT_SECURE_NO_WARNINGS.`. Personally I would take the second option. MSVC has a habit of discouraging you from using perfectly reasonable code because they consider it insecure. It's only insecure if you don't know what you are doing. – john Dec 09 '20 at 16:49
  • @Artefacto, when I cast jbyteArray into char *, it is successfully write it, but i need to write it as a jbyteArray, because I need to compare jbyteArray's in java and c++. Therefore I need to write jbyteArray as jbyteArray not as char *. – ozer Dec 09 '20 at 17:11
  • @john I edited the question. – ozer Dec 09 '20 at 17:15
  • @ozer To answer the question then we need to know how Java writes jbyteArrays to a file. Can you describe that? Or you could change your Java code so that it writes a jbyteArray in the same way as C++ writes a `char*`. The problem I'm sensing here is that you're trying to solve a problem which has not been fully defined. You need to get that straight first. Decide what format you want both sides to be using, then write the code to do that. Only when you have both sides working independently of each other should you start comparing outputs. – john Dec 09 '20 at 18:56

1 Answers1

2

You need to get a jbyte* from the jbytearray, which is a Java object:

public class Sample {
    public static final native void write(byte[] byteArray);
}
#include <jni.h>
#include <fstream>

extern "C" JNIEXPORT void JNICALL Java_Sample_write(JNIEnv *env,
                                                    jclass,
                                                    jbyteArray jba) {
    jbyte *arr = env->GetByteArrayElements(jba, nullptr);
    if (!arr) {
        return;
    }
    jint len = env->GetArrayLength(jba);

    std::ofstream("myfile.bin", std::ios::binary)
            .write(reinterpret_cast<char *>(arr), len);

    env->ReleaseByteArrayElements(jba, arr, JNI_ABORT);
}

You can test with:

project(sample_jni)
cmake_minimum_required(VERSION 2.8.8)

include(FindJNI)
if (JNI_FOUND)
    message(STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
    message(STATUS "JAVA_JVM_LIBRARY=${JAVA_JVM_LIBRARY}")
else()
    message(FATAL_ERROR "Found JNI: failed")
endif()

if(MSVC)
    add_definitions(-D_CRT_SECURE_NO_WARNINGS=1 -Dstrdup=_strdup -Dputenv=_putenv)
endif()

if(NOT(MSVC))
    add_compile_options(-Wall -Wno-padded -Wno-unknown-pragmas -Wno-switch -Werror)
endif()

set(SOURCE_FILES
    jni.cpp)
add_library(sample_jni SHARED ${SOURCE_FILES})

set_target_properties(sample_jni PROPERTIES
    C_VISIBILITY_PRESET hidden)

target_include_directories(sample_jni PRIVATE ${JNI_INCLUDE_DIRS})
import java.nio.charset.Charset;

public class Main {
    public static void main(String[] args) {
        System.loadLibrary("sample_jni");
        byte[] bytes = args[0].getBytes(Charset.forName("UTF-8"));
        Sample.write(bytes);
    }
}

After compiling both the Java classes and the native lib:

$ java -Djava.library.path=$(pwd) -cp . Main foobar
$ cat myfile.bin 
foobar
Artefacto
  • 96,375
  • 17
  • 202
  • 225