2014-02-26 3 views
0

Я снова возился с интерфейсом java natve, и я столкнулся с другой интересной проблемой. Я отправляю путь к файлу c через jni, а затем выполняю некоторые операции ввода-вывода. Таким образом, наиболее распространенными чертами, с которыми я столкнулся, является 'äåö'. Вот краткая демонстрация программы с точно такой же проблемой:Java JNI: Передача многобайтовых символов с java на c

Java:

public class java { 

    private static native void printBytes(String text); 
    static{ 
    System.loadLibrary("dll"); 
    } 

    public static void main(String[] args){ 
    printBytes("C:/Users/ä-å-ö/Documents/Bla.txt"); 
    } 
} 

C:

#include "java.h" 
#include <jni.h> 

JNIEXPORT void JNICALL Java_java_printBytes(JNIEnv *env, jclass class, jstring text){ 
    const jbyte* text_input = (*env)->GetStringUTFChars(env, text, 0); 
    jsize size = (*env)->GetStringUTFLength(env, text); 
    int i = 0; 
    printf("%s\n",text_input); 
    (*env)->ReleaseStringUTFChars(env, text, text_input); 
} 

Выход: C:/Users/├ñ-├Ñ-├Â/Документы/Bla.txt

Это NOT мой желаемый результат, я бы хотел, чтобы он выводил ту же строку, что и в java.

ответ

3

Вы имеете дело с спецификой кодирования символов для конкретной платформы. Хотя стандартный c printf должен иметь возможность обрабатывать многобайтовые (utf-8) закодированные строки, то окна/msvc обеспечивают одно, но не стандартное и не могут. На стандартной нестандартной платформе вы ожидаете, что ваш код будет работать. Строка, поступающая из java, находится в UTF-8 (многобайтовый символ), а MS printf ожидает ASCII (один байт на символ). Это работает для символов ASCII, потому что в UTF-8 эти символы имеют одинаковое значение. Он не работает для символов вне ASCII.

В основном вам нужно либо преобразовать строку в широкие символы (text.getBytes(Charset.forName(UTF-16LE"))), и передать ее как массив от java до c или преобразовать многобайтовую строку в широкие символы в c после ее получения (MultiByteToWideChar(CP_UTF8, ...)). Затем вы можете использовать printf («% S») или wprintf («% s») для вывода.

Для получения дополнительной информации см. Printing UTF-8 strings with printf - wide vs. multibyte string literals. Также обратите внимание, что в ответе говорится, что вы должны установить режим вывода Unicode с _setmode, если вы хотите получать unicode на консоли Windows.

Также обратите внимание, что я не верю, что GetStringUTFLength гарантирует терминатор NUL, но он слишком длинный.

+0

Спасибо, Грэм, это очень приятное и простое объяснение, но я использую внешнюю библиотеку в своей реальной программе. И он не принимает w_char к сожалению. Есть ли способ применить это к обычному массиву char в c? Это было бы безупречно. -Службы – Linus

+0

Igg. Хм, не зная подробностей библиотеки, сказать сложно. В зависимости от потребностей вашего языка вы можете уйти с [ISO-8859-1] (https://en.wikipedia.org/wiki/ISO/IEC_8859-1). Попробуйте это вместо UTF-16LE выше. – Graham

+0

Я использую библиотеку Matio, но как правильно использовать функцию MultiByteToWideChar? Я видел [это] (http://stackoverflow.com/a/3999597/3013334) сообщение об этом, но он использовал C++, спасибо! – Linus