【问题标题】:Uploading a File Using 'application/x-www-form-urlencoded'使用 'application/x-www-form-urlencoded' 上传文件
【发布时间】:2011-11-15 00:23:36
【问题描述】:

我想使用 C# 和 'application/x-www-form-urlencoded' 方法上传文件。我见过的所有示例都首先将文件数据读入字节数组,但这对我不起作用,因为我发送的文件超过 500MB。所以我正在寻找一种直接从磁盘流式传输文件的方法。

这个问题的一个好处是从指定的字节位置读取文件,例如,不是从第一个字节开始到最后一个字节,我可以从第 500 个字节开始到最后一个字节。

【问题讨论】:

    标签: c# .net


    【解决方案1】:

    你应该分块写入数据,所以上传的主要部分应该是这样的

    var buffer = new byte[4096];
    int bytesRead;
    while ((bytesRead = fileData.Read(buffer, 0, buffer.Length)) != 0)
         requestStream.Write(buffer, 0, bytesRead);
    

    所有上传代码。

    public static class Upload
    {
        private const string FileFieldNameDefault = "fileContent";
    
        public static WebResponse PostFile
            (Uri requestUri, NameValueCollection postData, Stream fileData, string fileName,
             string fileContentType, string fileFieldName, CookieContainer cookies,
             NameValueCollection headers)
        {
            ServicePointManager.Expect100Continue = false; 
    
            if (requestUri.Scheme == "https") 
            {
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
    
                ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, err) => true;
            }
    
            var webRequest = (HttpWebRequest)WebRequest.Create(requestUri);
    
            webRequest.Method = "POST";
    
            string boundary = "----------" + DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture);
    
            webRequest.ContentType = "multipart/form-data; boundary=" + boundary;
    
            string ctype;
    
            if (string.IsNullOrEmpty(fileContentType))
                fileContentType = TryGetContentType(fileName, out ctype)
                                    ? ctype
                                    : "application/octet-stream";
    
            fileFieldName = string.IsNullOrEmpty(fileFieldName) ? FileFieldNameDefault : fileFieldName;
    
            if (headers != null)
                foreach (string key in headers.AllKeys)
                {
                    var values = headers.GetValues(key);
                    if (values != null)
                        foreach (var value in values)
                            webRequest.Headers.Add(key, value);
                }
    
            if (cookies != null)
                webRequest.CookieContainer = cookies;
    
            var sbHeader = new StringBuilder();
    
            if (fileData != null)
            {
                var fileNameValue = string.Empty;
    
                if (string.IsNullOrEmpty(fileName) == false)
                    fileNameValue = string.Format(CultureInfo.InvariantCulture, "filename=\"{0}\"", Path.GetFileName(fileName));
    
                sbHeader
                    .AppendFormat("--{0}", boundary)
                    .AppendLine()
                    .AppendFormat("Content-Disposition: form-data; name=\"{0}\"; {1}", fileFieldName, fileNameValue)
                    .AppendLine()
                    .AppendFormat("Content-Type: {0}", fileContentType)
                    .AppendLine()
                    .AppendLine();
            }
    
            var sbFooter = new StringBuilder();
            sbFooter.AppendLine();
    
            if (postData != null)
                foreach (var key in postData.AllKeys)
                {
                    var values = postData.GetValues(key);
                    if (values != null)
                        foreach (var value in values)
                            sbFooter
                                .AppendFormat("--{0}", boundary)
                                .AppendLine()
                                .AppendFormat("Content-Disposition: form-data; name=\"{0}\"", key)
                                .AppendLine()
                                .AppendLine()
                                .Append(value)
                                .AppendLine();
                }
    
            sbFooter.AppendFormat("--{0}--\r\n", boundary);
    
            byte[] header = Encoding.UTF8.GetBytes(sbHeader.ToString());
            byte[] footer = Encoding.UTF8.GetBytes(sbFooter.ToString());
            long contentLength = header.Length + (fileData != null ? fileData.Length : 0) + footer.Length;
    
            webRequest.ContentLength = contentLength;
    
            using (var requestStream = webRequest.GetRequestStream())
            {
                requestStream.Write(header, 0, header.Length);
    
                if (fileData != null)
                {
                    var buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = fileData.Read(buffer, 0, buffer.Length)) != 0)
                        requestStream.Write(buffer, 0, bytesRead);
                }
    
                requestStream.Write(footer, 0, footer.Length);
    
                return webRequest.GetResponse();
            }
        }
    
        public static WebResponse PostFile
            (Uri requestUri, NameValueCollection postData, string fileName,
             string fileContentType, string fileFieldName, CookieContainer cookies,
             NameValueCollection headers)
        {
            using (var fileData = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                return PostFile(requestUri, postData, fileData,
                                fileName, fileContentType, fileFieldName, cookies,
                                headers);
        }
    
        private static bool TryGetContentType(string fileName, out string contentType)
        {
            try
            {
                RegistryKey key = Registry.ClassesRoot.OpenSubKey(@"MIME\Database\Content Type");
    
                if (key != null)
                {
                    foreach (string keyName in from keyName in key.GetSubKeyNames()
                                               let subKey = key.OpenSubKey(keyName)
                                               where subKey != null
                                               let subKeyValue = (string)subKey.GetValue("Extension")
                                               where string.IsNullOrEmpty(subKeyValue) == false
                                               where string.Compare(Path.GetExtension(fileName), subKeyValue, StringComparison.OrdinalIgnoreCase) == 0
                                               select keyName)
                    {
                        contentType = keyName;
                        return true;
                    }
                }
            }
            catch
            {
                // fail silently
                // TODO: rethrow registry access denied errors
            }
            contentType = string.Empty;
            return false;
        }
    }
    

    【讨论】:

    • 啊,是的。分块写。不知道为什么我没有想到这一点。当我询问“application/x-www-form-urlencoded”时,我将让您的示例使用“multipart/form-data”。 :)
    • 这只是我的工作代码,抱歉,我没有太多时间用application/x-www-form-urlencoded进行更改和测试
    • 获取您上传的文件的任何示例代码? requestUri 的 Page_Load 源码示例?
    猜你喜欢
    • 1970-01-01
    • 2017-09-11
    • 2014-03-30
    • 2019-02-04
    • 1970-01-01
    • 2018-10-05
    • 2018-11-17
    • 1970-01-01
    • 2020-09-06
    相关资源
    最近更新 更多