C# 将大字符串转换为UTF-8

C# 将大字符串转换为UTF-8,c#,wcf,rest,utf-8,C#,Wcf,Rest,Utf 8,我有一个WCF4REST服务,它查询数据库并返回JSON。有些用户希望进行非常大的查询,尽管我很难返回字符串。例如,我需要返回一个500M JSON字符串(所有数据都是ASCII文本),但当我尝试从.NET的本机UTF-16转换字符串时,遇到了OutOfMemoryException。这是我正在做的一个简单的例子 [WebInvoke(UriTemplate="/RunQuery", ResponseFormat=WebMessageFormat.Json)] public Stream Run

我有一个WCF4REST服务,它查询数据库并返回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.ToCharray。我尝试过对字符串进行分块以构建字节数组,但似乎没有任何效果。你知道我如何在不爆炸的情况下发送这些数据吗?

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

您应该能够通过提取输入字符串的一部分,将它们逐块转换为utf 8来实现这一点


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

如果必须返回流,请使用文件流或至少预先分配内存流空间

如果必须使用500Mb字符串:

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

  • 使用编写器-在将JSON写入输出时,编写器可以轻松(即)直接编码到输出。作为补充建议,不要创建JSON字符串,而是将输出写入Writer

  • 如果您知道您的字符串仅为ASCII码,那么您可以通过将每个字符转换为字节来编写流来作弊


5亿美元?哎哟您不能将数据拆分为页面吗?只是一个猜测:您可以尝试将响应数据分块写入临时文件,然后为临时文件返回一个打开的流吗?(您最好重新构造DoQuery(),使其支持将结果写入输出流,而不是返回流。如果不需要,您确实不应该缓冲整个兆字节的数据。)或者将数据流回客户端。。。。(现在我想知道是否有一种方法可以让WCF服务直接将输出流传递给代码,而不必将输入流返回到响应中。)500 MB Json对于服务器和客户端来说都非常庞大。我会尝试将结果分块发送(http支持这一点)虽然每个区块都包含一个有效的json。类似于twitters stream API(),但不幸的是,我的服务必须是32位的,才能使用Oracle odp.net驱动程序(Oracle.DataAccess.dll),它似乎没有64位的风格它死掉了,可能是因为我的内存中有一个500000000字符串。这确实绕过了整个字节数组,这很有帮助。JSON是由JavaScriptSerializer生成的,它让我可以选择字符串或StringBuilder作为输出。我希望我可以简单地返回序列化对象,但它使用嵌套字典…我明白了-你在32位进程中必须非常小心地处理大的结果,即2这样的请求同时会杀死服务器。考虑使用JSON.NET序列化程序(JSON.COUDULSEX.COM)因为它比内置的更灵活,比如-。否则我看到的唯一选择是编写自己的JSON序列化并直接写入响应流。。。