【问题标题】:How to convert chunck by chunck byte array into base64 string?如何逐块字节数组将块转换为base64字符串?
【发布时间】:2016-05-12 12:05:58
【问题描述】:

我们正在读取文件的字节数组并将其转换为base64字符串,如下所示

    public static string ZipToBase64()
            {
                FileUpload fileCONTENT = FindControl("FileUploadControl") as FileUpload;

                byte[] byteArr = fileCONTENT.FileBytes;

                return Convert.ToBase64String(byteArr);

            }

    string attachmentBytes = ZipToBase64();
    string json1 = "{ \"fileName\": \"Ch01.pdf\", \"data\": " + "\"" + attachmentBytes + "\"}";

当我们尝试将最大 1 GB 的大文件转换为 base64 字符串时,它会抛出内存不足异常。我们正在将此 json 发送到 restful wcf 服务。以下是我在 RESTful WCF 服务中的方法。

 [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.WrappedRequest, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public void UploadFile1(Stream input)
        {

            string UserName = HttpContext.Current.Request.Headers["UserName"];
            string Password = Sql.ToString(HttpContext.Current.Request.Headers["Password"]);
            string sDevideID = Sql.ToString(HttpContext.Current.Request.Headers["DeviceID"]);
            string Version = string.Empty;
            if (validateUser(UserName, Password, Version, sDevideID) == Guid.Empty)
            {
                SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), "Invalid username or password for " + UserName);
                throw (new Exception("Invalid username or password for " + UserName));
            }


            string sRequest = String.Empty;
            using (StreamReader stmRequest = new StreamReader(input, System.Text.Encoding.UTF8))
            {
                sRequest = stmRequest.ReadToEnd();
            }
            // http://weblogs.asp.net/hajan/archive/2010/07/23/javascriptserializer-dictionary-to-json-serialization-and-deserialization.aspx

            JavaScriptSerializer json = new JavaScriptSerializer();
            // 12/12/2014 Paul.  No reason to limit the Json result. 
            json.MaxJsonLength = int.MaxValue;

            Dictionary<string, string> dict = json.Deserialize<Dictionary<string, string>>(sRequest);
            string base64String = dict["data"];
            string fileName = dict["fileName"];


            byte[] fileBytes = Convert.FromBase64String(base64String);
            Stream stream = new MemoryStream(fileBytes);

            //FileStream fs1 = stream as FileStream;

            string networkPath = WebConfigurationManager.AppSettings["NetWorkPath"];
            File.WriteAllBytes(networkPath + "/" + fileName, fileBytes); // Requires System.IO
        }

请提供大字节数组转base64字符串的解决方案

【问题讨论】:

  • 将 1GB base64 编码的字符串作为 json 发送不是一个好主意,你不觉得吗?
  • @Evk 感谢您的评论。我们正在使用 android 移动应用程序和 Web 应用程序来上传文件。我们正在文件系统上的远程服务器上上传文件。这就是为什么我编写了用于上传文件的 RESTFul wcf 服务
  • 但我的意思是——如果你的文件很大(超过 10MB)——你永远不应该通过 json 序列化它们。您必须以流式方式在请求正文中传递它们。对于 RESTful wcf 服务也是如此。我本可以展示如何将 byte[] 逐块转换为 base64,但这不会帮助你。
  • @Evk 是的,我们在同一页上。我已将 json 以流式方式传递给 WCF 服务。我已经更新了我的问题。请参见。请提供base64字符串中逐块转换字节数组的解决方案

标签: c# asp.net base64 bytearray chunks


【解决方案1】:

您在 wcf 服务中使用 Stream 输入这一事实并不意味着您以流式方式传递任何内容。事实上,在你的情况下你没有,因为:

  1. 您在客户端的内存中缓冲整个文件以构建 json 字符串。
  2. 你通过stmRequest.ReadToEnd()在内存中缓存服务器上的整个文件。

因此不会发生流式传输。首先你应该意识到这里不需要 json - 你只需要在你的 http 请求正文中传递文件。您首先应该做的是在您的 UploadFile1 方法中丢弃所有低于安全检查的代码,而是这样做:

public void UploadFile1(string fileName, Stream input) {
    // check your security headers here
    string networkPath = WebConfigurationManager.AppSettings["NetWorkPath"];
    using (var fs = File.Create(networkPath + "/" + fileName)) {
        input.CopyTo(fs);
    }
}

这里我们只是将输入流复制到输出流(文件),没有任何缓冲(当然CopyTo 会缓冲块,但它们会非常小)。标记您的服务方法:

[WebInvoke(Method = "POST", UriTemplate = "/UploadFile1/{fileName}")]

允许您在查询字符串中传递文件名。

现在给客户。不确定您使用哪种方法与服务器通信,我将展示原始 HttpWebRequest 的示例。

var filePath = "path to your zip file here";
var file = new FileInfo(filePath);
// pass file name in query string
var request = (HttpWebRequest)WebRequest.Create("http://YourServiceUrl/UploadFile1/" + file.Name);            
request.Method = "POST";
// set content length
request.ContentLength = file.Length;
// stream file to server
using (var fs = File.OpenRead(file.FullName)) {
    using (var body = request.GetRequestStream()) {
         fs.CopyTo(body);
    }
}
// ensure no errors
request.GetResponse().Dispose();

【讨论】:

  • 我在编译 wcf 服务时出错。使用“UriTemplate”的端点不能与“System.ServiceModel.Description.WebScriptEnablingBehavior”一起使用。
  • 见这里:blogs.msdn.microsoft.com/justinjsmith/2008/02/15/…。如果没有任何帮助 - 在标题中传递文件名而不是查询字符串。我实际上讨厌 WCF,因为这些小问题无处不在,并且已经多年没有使用它(并且从未回头)。
  • 我已经在 header 中传递了文件名。
  • 我现在也可以上传大文件了。当我尝试上传大于 500 MB 的文件时,有时会在 request.GetRequestStream 和 fs.CopyTo(body) 出现超时异常。然后我点击了这个链接thomaslevesque.com/2014/01/14/… 现在一切正常。
  • 谢谢@Evk。你帮了我很多
猜你喜欢
  • 2016-10-21
  • 2013-04-06
  • 2012-07-21
  • 2017-05-21
  • 1970-01-01
  • 2016-10-21
  • 2011-09-21
  • 2017-07-10
  • 1970-01-01
相关资源
最近更新 更多