如何将 jstring 转换为 wchar_t *

How do I convert jstring to wchar_t *

提问人: 提问时间:9/16/2008 最后编辑:piyushj 更新时间:7/15/2019 访问量:20647

问:

假设在 C++ 端,我的函数采用一个名为 的变量。我可以将其转换为ANSI字符串,如下所示:jstringmyString

const char* ansiString = env->GetStringUTFChars(myString, 0);

有没有办法得到

const wchar_t* unicodeString =...

java c++ java-native-interface(java c++java-native-interface)

评论


答:

3赞 C. K. Young 9/16/2008 #1

一个可移植且强大的解决方案是使用 iconv,但您必须知道系统使用的编码(例如,Windows 上的 UTF-16,许多 Unix 系统上的 UTF-32)。wchar_t

如果你想尽量减少对第三方代码的依赖,你也可以手动滚动你自己的 UTF-8 转换器。如果转换为 UTF-32,这很容易,而使用 UTF-16 则更难,因为您还必须处理代理项对。:-P此外,您必须小心拒绝非最短的表单,否则在某些情况下可能会打开安全漏洞。

评论

0赞 Rup 1/5/2012
您建议将 jstring 转换为 UTF-8,然后再转换回 UTF-16?这真的有必要吗?
0赞 arkon 5/24/2012
@Rup jstring 已经是 UTF-8:“JNI 使用修改后的 UTF-8 字符串来表示各种字符串类型。修改后的 UTF-8 字符串与 Java VM 使用的字符串相同。对修改后的 UTF-8 字符串进行编码,以便仅包含非 null ASCII 字符的字符序列只能使用每个字符一个字节来表示,但可以表示所有 Unicode 字符。Java VM 无法识别标准 UTF-8 的四字节格式;它使用自己的二乘三字节格式。
0赞 Rup 5/24/2012
@b1naryatr0phy真的吗?我的系统(1.6 和 1.7)上的 jni.h 对我来说看起来更像是 UTF-16。typedef unsigned short jchar;
0赞 arkon 5/24/2012
我一定是误解了什么,这句话是直接从 Oracle 的文档中提取的: http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/types.html 如果可以的话,请随时解释,我仍然试图解决这个问题。
1赞 1800 INFORMATION 9/16/2008 #2

如果我们对跨平台能力不感兴趣,则可以在 Windows 中使用 MultiByteToWideChar 函数或有用的宏 A2W(参考示例)。

4赞 Adam Mitz 9/16/2008 #3

JNI 也有一个 GetStringChars() 函数。返回类型是 const jchar*,jchar 在 win32 上是 16 位,因此在某种程度上与 wchar_t 兼容。不确定它是真正的 UTF-16 还是其他东西......

评论

0赞 C. K. Young 9/16/2008
您碰巧知道 jchar 的字节排序是否与 Win32 wchar_t兼容吗?它应该是,但可以肯定的是,可能很好。:-)
0赞 Adam Mitz 9/16/2008
jchar 被 typedef'ed 为 unsigned short。我自己没有尝试过,但我的猜测是“是的”。
0赞 arkon 5/24/2012
char == jchar == 无符号 16 位
0赞 Adam Mitz 5/24/2012
char == 无符号 16 位在哪个平台上?
0赞 Adam Mitz 5/24/2012
为了减少混淆,在本次讨论中,“char”是ISO C和C++语言中的内置数据类型,而不是Java中的数据类型。
0赞 Roman Zhitnitskiy 4/30/2009 #4

只需使用 env->GetStringChars(myString, 0); Java 本质上是传递 Unicode

3赞 Benj 11/3/2009 #5

我知道这是一年前问过的,但我不喜欢其他答案,所以我无论如何都会回答。以下是我们在源代码中的做法:

wchar_t * JavaToWSZ(JNIEnv* env, jstring string)
{
    if (string == NULL)
        return NULL;
    int len = env->GetStringLength(string);
    const jchar* raw = env->GetStringChars(string, NULL);
    if (raw == NULL)
        return NULL;

    wchar_t* wsz = new wchar_t[len+1];
    memcpy(wsz, raw, len*2);
    wsz[len] = 0;

    env->ReleaseStringChars(string, raw);

    return wsz;
}

编辑:此解决方案在wchar_t为 2 字节的平台上运行良好,某些平台具有 4 字节wchar_t在这种情况下,此解决方案将不起作用。

评论

2赞 Kobor42 1/27/2012
这个解决方案是错误的。因此,我吸了 12 个小时。wchar_t 和 jchar 不一定是一样的。证明这一点的是我的测试程序的输出:01-26 20:28:43.675: E/[LMI-NATIVE](9280): len: 7, jchar: 2, wchar: 4
2赞 Benj 1/27/2012
@Kobor42 - 您的测试程序是做什么的?你是说你找到了一个 wchar_t 是 4 字节的实例吗?我实际上没有意识到这一点,但这个函数被设计为(主要)在 Windows 上运行,其中wchar_t始终是 2。我现在意识到wchar_t是特定于编译器的,并且可能在您的平台上有所不同。
0赞 Kobor42 5/18/2012
完全。在 Android 2.1 之前的版本上,wchar_t为 1 字节。2.1 及之后为 4 个字节。
0赞 rustyx 5/27/2012
您正在混合可能不兼容的类型。Java 始终是 UTF-16。但并不总是 UTF-16,有时是 UTF-32。在这种情况下,您需要将 UTF-16 转换为 UTF-32(这不仅仅是将 jchar 填充为 4 个字节的问题,有关详细信息,请参见 en.wikipedia.org/wiki/UTF-16)。jcharwchar_t
0赞 Kobor42 7/12/2012
我不是在混合它。NDK 正在混合它。我想将没有信息丢失的 java 字符串转换为 c 字符串。
4赞 Andreas Rieder 2/19/2010 #6

谁释放了wsz? 我会推荐STL!

std::wstring JavaToWSZ(JNIEnv* env, jstring string)
{
    std::wstring value;
    if (string == NULL) {
        return value; // empty string
    }
    const jchar* raw = env->GetStringChars(string, NULL);
    if (raw != NULL) {
        jsize len = env->GetStringLength(string);
        value.assign(raw, len);
        env->ReleaseStringChars(string, raw);
    }
    return value;
}

评论

0赞 Benj 1/10/2012
除非使用 C++11,否则这不是一个很好的解决方案,因为 wstring 将按值返回。(显然,在 C++11 之后,它将被移动构造,这将是有效的)
4赞 mjaggard 4/17/2012
值分配(raw, len);无效。我认为它应该是value.assign(raw, raw + len);但我还没有测试过。
0赞 bbqchickenrobot 8/30/2012
太好了 - 在 C# -> C++/CLI -> JNI -> Java 应用程序中完美地为我工作!
0赞 Greg Domjan 5/29/2015
无论 GetStringChars 是否成功,您都不必调用 ReleaseStringChars,否则 jstring 可能会被固定并“泄漏”
0赞 Vladimir Ivanov 11/11/2010 #7

相当简单。但不要忘记通过 ReleaseStringChars 释放内存

JNIEXPORT jboolean JNICALL Java_TestClass_test(JNIEnv * env, jobject, jstring string)
{
    const wchar_t * utf16 = (wchar_t *)env->GetStringChars(string, NULL);
    ...
    env->ReleaseStringChars(string, utf16);
}
13赞 gergonzalez 2/2/2012 #8

如果这对某人有帮助......我已将此功能用于 Android 项目:

std::wstring Java_To_WStr(JNIEnv *env, jstring string)
{
    std::wstring value;

    const jchar *raw = env->GetStringChars(string, 0);
    jsize len = env->GetStringLength(string);
    const jchar *temp = raw;
    while (len > 0)
    {
        value += *(temp++);
        len--;
    }
    env->ReleaseStringChars(string, raw);

    return value;
}

一个改进的解决方案可能是(感谢您的反馈):

std::wstring Java_To_WStr(JNIEnv *env, jstring string)
{
    std::wstring value;

    const jchar *raw = env->GetStringChars(string, 0);
    jsize len = env->GetStringLength(string);

    value.assign(raw, raw + len);

    env->ReleaseStringChars(string, raw);

    return value;
}

评论

0赞 Rup 2/2/2012
很整洁,尽管我怀疑一次性加载带有缓冲区的字符串会比一次加载一个字符更有效。
1赞 Stevens Miller 7/20/2016
C++ 编译器是否注意到您正在返回一个自动值,并将其分配到堆而不是堆栈上?
0赞 shizhen wang 12/10/2018 #9

我尝试jstring->char->wchar_t

char* js2c(JNIEnv* env, jstring jstr)
{
    char* rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("utf-8");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr = (jbyteArray)env->CallObjectMethod(jstr, mid, strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE);
    if (alen > 0)
    {
        rtn = (char*)malloc(alen + 1);
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    env->ReleaseByteArrayElements(barr, ba, 0);
    return rtn;
}

jstring c2js(JNIEnv* env, const char* str) {
    jstring rtn = 0;
    int slen = strlen(str);
    unsigned short * buffer = 0;
    if (slen == 0)
        rtn = (env)->NewStringUTF(str);
    else {
        int length = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, NULL, 0);
        buffer = (unsigned short *)malloc(length * 2 + 1);
        if (MultiByteToWideChar(CP_ACP, 0, (LPCSTR)str, slen, (LPWSTR)buffer, length) > 0)
            rtn = (env)->NewString((jchar*)buffer, length);
        free(buffer);
    }
    return rtn;
}



jstring w2js(JNIEnv *env, wchar_t *src)
{
    size_t len = wcslen(src) + 1;
    size_t converted = 0;
    char *dest;
    dest = (char*)malloc(len * sizeof(char));
    wcstombs_s(&converted, dest, len, src, _TRUNCATE);

    jstring dst = c2js(env, dest);
    return dst;
}

wchar_t *js2w(JNIEnv *env, jstring src) {

    char *dest = js2c(env, src);
    size_t len = strlen(dest) + 1;
    size_t converted = 0;
    wchar_t *dst;
    dst = (wchar_t*)malloc(len * sizeof(wchar_t));
    mbstowcs_s(&converted, dst, len, dest, _TRUNCATE);
    return dst;
}
0赞 Eng.Fouad 7/15/2019 #10

这是我如何转换为 .jstringLPWSTR

const char* nativeString = env->GetStringUTFChars(javaString, 0);
size_t size = strlen(nativeString) + 1;
LPWSTR lpwstr = new wchar_t[size];
size_t outSize;
mbstowcs_s(&outSize, lpwstr, size, nativeString, size - 1);