有问题的函数是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。可能就是答案。
答案提出了一个不安全的解决方案。这使得该应用程序无法验证,如果有任何其他解决方案,则价格太高。请不要不安全。
答案 0 :(得分:0)
这个怎么样:
/// <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());
}