【问题标题】:How to marshall utf-8 string in C#如何在 C# 中编组 utf-8 字符串
【发布时间】:2016-05-20 03:13:22
【问题描述】:

有问题的函数是 Sqlite 的原生 C API 的一部分,但答案应该是通用的。我很惊讶我找不到答案。

现有代码看起来像这样,但只处理 8 位 ANSI。

// wrapper to handle marshalling and avoid nulls
public static string sqlite3_column_text_wrapper(IntPtr pstmt, int iCol) {
  var ptr = sqlite3_column_text(pstmt, iCol);
  if (ptr == IntPtr.Zero) return "";
  else return Marshal.PtrToStringAnsi(ptr);
}

// wrapper to handle marshalling and avoid nulls // TODO: utf
public static string sqlite3_column_text_wrapper_utf(IntPtr pstmt, int iCol) {
  var ptr = sqlite3_column_text(pstmt, iCol);
  if (ptr == IntPtr.Zero) return "";
  else return Marshal.PtrToStringAnsi(ptr);
}

[DllImport("sqlite3.dll", CallingConvention = CallingConvention.Cdecl)] public static extern IntPtr sqlite3_column_text(IntPtr pstmt, int iCol);

问题是如何对 utf-8 做同样的事情,最好不必分配缓冲区和复制数据两次。

肯定有“最好的方法”吗?


我发现了这个:C# callback receiving UTF8 string,它使用 MultiByteToWideChar(两次)和 StringBuilder。可能就是答案。


答案提出了一个不安全的解决方案。这使得应用程序无法验证,如果有任何其他解决方案可用,这代价太高了。请不要不安全。

【问题讨论】:

  • 我删除了关于 Marshal.PtrToStringUni() 的答案,因为正如您所指出的,它适用于 UTF-16,而不是 UTF-8。也许您应该将字节数组编组为 c# 并使用 Encoding.UTF8.GetString(bytes) 将其转换为字符串。但是您需要以某种方式知道字节数组的长度才能对其进行编组。
  • @George:有趣的是,我可能会用完这个函数,因为 Sqlite 有一个 text16() 版本。但你是对的,它无法按要求回答问题。

标签: c# sqlite utf-8 marshalling


【解决方案1】:

这个怎么样:

    /// <summary>
    /// Converts a byte pointer to a UTF8 encoded string.
    /// </summary>
    /// <param name="bytePtr">The byte PTR.</param>
    /// <returns></returns>
    public static unsafe string BytePtrToStringUTF8(byte* bytePtr)
    {
        if (bytePtr == null) return null;
        if (*bytePtr == 0) return string.Empty;

        var byteBuffer = new List<byte>(1024);
        var currentByte = default(byte);

        while (true)
        {
            currentByte = *bytePtr;
            if (currentByte == 0)
                break;

            byteBuffer.Add(currentByte);
            bytePtr++;
        }

        return Encoding.UTF8.GetString(byteBuffer.ToArray());
    }

【讨论】:

  • 嗯,这是不安全的,看起来它分配了一个缓冲区并复制了两次数据。这是我试图避免的。
猜你喜欢
  • 2013-01-31
  • 2016-01-11
  • 2017-03-04
  • 1970-01-01
  • 2012-09-11
  • 1970-01-01
  • 2023-03-27
  • 2014-06-09
  • 2013-06-17
相关资源
最近更新 更多