如何将字节数组转换为字符串数组?

问题描述:

只是为了澄清事情。我是而不是试图将字节数组转换为单个字符串。我试图将字节数组转换为字符串数组。如何将字节数组转换为字符串数组?

我使用GetClipboardData API从剪贴板获取一些数据,然后我将数据从内存复制为字节数组。当你复制多个文件(因此为CF_HDROP剪贴板格式)时,我想将此字节数组转换为复制文件的字符串数组。

这是我的代码到目前为止。

//Get pointer to clipboard data in the selected format 
var clipboardDataPointer = GetClipboardData(format); 

//Do a bunch of crap necessary to copy the data from the memory 
//the above pointer points at to a place we can access it. 
var length = GlobalSize(clipboardDataPointer); 
var @lock = GlobalLock(clipboardDataPointer); 

//Init a buffer which will contain the clipboard data 
var buffer = new byte[(int)length]; 

//Copy clipboard data to buffer 
Marshal.Copy(@lock, buffer, 0, (int)length); 

GlobalUnlock(clipboardDataPointer); 

snapshot.InsertData(format, buffer); 

现在,这里是我之后读取缓冲区数据的代码。

var formatter = new BinaryFormatter(); 
using (var serializedData = new MemoryStream(buffer)) 
{ 
    paths = (string[]) formatter.Deserialize(serializedData); 
} 

这是行不通的,它会用一个异常说,流不包含二进制头崩溃。我想这是因为它不知道要反序列化的类型。

我试过看Marshal类。没有什么关系。

+0

你思考['Clipboard.GetFileDropList()'](http://msdn.microsoft.com/en-us/library/system.windows.forms.clipboard。 getfiledroplist.aspx)? – GSerg 2012-07-25 19:11:10

+0

是的,但我想单独使用Windows API,因为WPF中的常规剪贴板功能有问题,正如Web上的许多地方所述。 – 2012-07-25 19:12:09

如果数据通过Win32 API传递,那么字符串数组将只是一个以null结尾的字符串序列,并在末尾带有一个双空终止符。 (注意字符串将是UTF-16,所以两个字符每个字符字节)。你基本上需要一次将一个字符串拉出到一个数组中。

您在此寻找的方法是Marshal.PtrToStringUni,您应该使用该方法,而不是Marshal.Copy,因为它适用于IntPtr。它将从您的IntPtr中提取一个字符串,直到第一个空字符,并将其复制到字符串中。

想法是继续提取单个字符串,然后将IntPtr超过空字节前进到下一个字符串的开头,直到您用完缓冲区。我已经没有进行了测试,它也许可以改善(尤其是我觉得有检测缓冲区的末尾一个更聪明的方式),但基本的想法是:

var myptr = GetClipboardData(format); 
var length = GlobalSize(myptr); 

var result = new List<string>(); 

var pos = 0; 
while (pos < length) 
{ 
    var str = Marshal.PtrToStringUni(myptr); 
    var count = Encoding.Unicode.GetByteCount(str); 

    myptr = IntPtr.Add(myptr, count + 1); 
    pos += count + 1; 

    result.Add(str); 
} 

return result.ToArray(); 

(顺便说一句:你的反序列化不起作用的原因是因为序列化一个string[]不只是将字符写成字节;而是写出了一个字符串数组的结构,包括.NET使用的其他内部位,如长度,以及带有类型信息的二进制头文件。从剪贴板返回的内容不存在,因此无法反序列化。)

如何:

var strings = Encoding.Unicode 
    .GetString(buffer) 
    .Split(new[] { '\0' }, StringSplitOptions.RemoveEmptyEntries);