将大字符串转换为UTF-8

时间:2012-01-27 20:30:40

标签: c# wcf rest utf-8

我有一个WCF4 REST服务,它查询数据库并返回JSON。有些用户想要进行非常大的查询,尽管我很难返回字符串。例如,我需要返回一个500M的JSON字符串(所有数据都是ASCII文本),但是当我尝试从.NET的原生UTF-16转换字符串时,我遇到了OutOfMemoryException。这是我正在做的一个紧凑的样本。

[WebInvoke(UriTemplate="/RunQuery", ResponseFormat=WebMessageFormat.Json)]
public Stream RunQuery() {
    // Perform query and return serialized json string (~500 million ASCII characters)
    string json = DoQuery(HttpContext.Current.Request.Form);
    // Set output charset
    WebOperationContext.Current.OutgoingResponse.ContentType = "application/json; charset=utf-8";
    // Convert UTF-16 string to UTF-8 (OutOfMemoryException)
    byte jsonBytes[] = System.Text.Encoding.UTF8.GetBytes(json)
    // Send UTF-8 string, without BOM
    return new MemoryStream(jsonBytes);
}

仅当我将JSON保持在200M左右时才有效。当它运行时,我看到IIS进程的内存使用率上升,然后爆炸到2.8G,此时它就会死掉。 stacktrace报告它发生在System.String.ToCharArray。我尝试过对字符串进行分块以构建字节数组,但似乎没有任何效果。知道如何在不爆炸的情况下发送这些数据吗?

2 个答案:

答案 0 :(得分:0)

您可以通过编写自己的stream实现来解决此问题,该实现可以动态地将输入转换为utf8。

你应该可以通过提取部分输入字符串,将它们逐块转换为utf 8来实现。

请记住,字节数不一定与字符数相同,除非您从不发送任何类型的国际字符。

答案 1 :(得分:0)

如果必须返回流 - 使用文件流或至少预先分配MemoryStream空间。

如果你必须坚持500Mb字符串:

  • 使用64位机器和64位进程。 x86进程不太可能成功分配该大小的2个内存。请注意,即使您使用64位进程,CLR也会限制大约2Gb的“单块分配”大小,使得1Gb字符串不太适合内存。因此,在接近500Mb的某个时刻 - 1Gb切换到64位将不再有用。

  • 使用Writers - 他们可以轻松地(即http://msdn.microsoft.com/en-us/library/3aadshsx.aspx)在向您输出JSON时直接编码到输出。作为额外的建议 - 甚至不要创建JSON字符串,而是将输出写入Writer。

  • 如果你知道你的字符串只是ASCII - 通过写入流来欺骗你自己将每个字符转换为字节。