Я пытаюсь преобразовать jbytearray в char* на Jni Layer. Однако его результат имеет неправильный характер, например:
07-23 10:22:43.701 26585-26646/com.zspirytus.androidlua D/ScriptPkgDataFetcher: getPkgData: 0028 at Kotlin
07-23 10:22:43.701 26585-26646/com.zspirytus.androidlua D/LuaEngine: getPkgData: 0028�ض
07-23 10:22:44.221 26585-26646/com.zspirytus.androidlua D/ScriptPkgDataFetcher: getPkgData: 0028 at Kotlin
07-23 10:22:44.221 26585-26646/com.zspirytus.androidlua D/LuaEngine: getPkgData: 0028�ض
07-23 10:22:44.721 26585-26646/com.zspirytus.androidlua D/ScriptPkgDataFetcher: getPkgData: 0028 at Kotlin
07-23 10:22:44.721 26585-26646/com.zspirytus.androidlua D/LuaEngine: getPkgData: 0028�ض
В Kotlin Layer результат типа String — "0028"; на слое Jni преобразованный результат равен "0028�ض". Вот что я делаю в своем коде:
В Kotlin функция возвращает массив байтов:
fun getContentByEntryName(entryName: String): ByteArray {
// data is always a String with value "0028"
val data = ZipFileUtils.getFileContentFromZipFile(ZipFile(scriptPkg), entryName)
Log.d("ScriptPkgDataFetcher", "getPkgDatagetPkgData: $data at Kotlin")
return data.toByteArray()
}
В Jni я конвертирую jbytearray в char* следующим образом:
jbyteArray jba = (jbyteArray) env->CallStaticObjectMethod(clazz, methodId, dataPath);
int len = env->GetArrayLength (jba);
char* buff = new char[len];
env->GetByteArrayRegion (jba, 0, len, reinterpret_cast<jbyte*>(buff));
Log_d(LOG_TAG, "getPkgData: %s", buff);
Кажется, что это не работает правильно. Я также пробую этот код, но он все еще не работать правильно...
jbyteArray jba = (jbyteArray) env->CallStaticObjectMethod(clazz, methodId, dataPath);
const char *cStr = (char *) (env)->GetByteArrayElements(jba, NULL);
Есть ли ошибка в моем коде? Помогите исправить, пожалуйста. Спасибо!
Если вы собираетесь использовать new char[] для создания строковых данных, а затем использовать эти данные в функциях, требующих нулевого завершения, вы должны явно добавить нулевой терминатор.
Кроме того, возможно, вы не выделили достаточно места для завершающего нуля, поэтому вам нужно выделить len + 1 байт.
Ты можешь это сделать:
char* buff = new char[len + 1]();
который заполняет буфер нулевыми символами или:
char* buff = new char[len + 1];
buff[len] = '\0';
Однако я настоятельно рекомендую вам использовать std::string или std::vector<char> вместо того, чтобы делать что-то таким образом.
Поскольку JNI очень хрупок, при возникновении исключения вы можете получить утечку памяти, используя необработанные указатели таким образом.
Вот небольшая процедура, которую вы можете использовать для преобразования массива байтов Java в вектор:
#include <vector>
//...
jbyteArray jba = (jbyteArray) env->CallStaticObjectMethod(clazz, methodId, dataPath);
int len = env->GetArrayLength (jba);
std::vector<char> buff(len + 1, 0);
env->GetByteArrayRegion (jba, 0, len, reinterpret_cast<jbyte*>(buff.data()));
Log_d(LOG_TAG, "getPkgData: %s", buff.data());
Это не повлияет на утечку памяти, если возникнет исключение, поскольку std::vector автоматически освободит память, когда вектор по какой-либо причине выйдет из области видимости.
Спасибо за ваш ответ, он работает правильно. Я не знаком с C/C++, как преобразовать jbytearray в строку или вектор?
Добавлена небольшая процедура для преобразования в вектор.
Спасибо за ваш ответ, я попробовал, и он работает правильно.
char* buff = new char[len];-- Это не завершает строковые данные нулем, что необходимо для правильной работы строк в стиле C.