读取上传数据流(1)
在 POST 方式的请求中,请求参数通过请求的 Body 部分提供,在多部分形式的请求中,通过边界来划分请求参数。在这一部分的代码中,主要是计算好边界的位置。为了便于读取上传的文件,MultipartStream 流专门用于读取多部分组成的数据,如代码清单2-7所示。
代码清单2-7 读取上传数据流 - using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
-
- using System.IO;
- using System.Web;
- using System.Text.RegularExpressions;
-
- namespace DiskFileUpload
- {
- public class MultipartStream : Stream
- {
- private System.Text.Encoding bodyEncoding =
System.Text.Encoding.UTF8; -
- private static int HEADER_PART_SIZE_MAX = 4096;
-
- private static byte[] HEADER_SEPARATOR =
new byte[] { 0xd, 0xa, 0xd, 0xa }; -
- // 匹配参数名称的正则表达式 . 表示除换行之外的所有字符
- // +? 表示懒惰模式
- private static readonly System.Text.
RegularExpressions.Regex nameRegex - = new System.Text.RegularExpressions.
Regex("name=\"(.+?)\""); -
- // 匹配上传文件名的正则表达式
- private static readonly System.Text.
RegularExpressions.Regex filenameRegex - = new System.Text.RegularExpressions.
Regex("filename=\"(.+)\""); -
- private static readonly System.Text.
RegularExpressions.Regex contentTypeRegex - = new Regex("Content-Type=\"(.+)\"");
-
- private byte[] boundary;
- private int boundaryLength;
-
- int[] next;
-
- // 流中内容的字节长度
- private long length;
- public override long Length
- {
- get { return this.length; }
- }
-
- // 当前位置
- public override long Position
- {
- get { return this.startIndex + this.bufferStart; }
- set { throw new Exception("不允许设置当前位置"); }
- }
-
- // 内部预读的缓冲区
- private byte[] buffer;
-
- // 缓冲内容的起始位置
- private int startIndex;
- private int bufferLength;
-
- // 缓冲区也不一定填满,缓冲区有内容部分的起始下标
- private int bufferStart;
- private int bufferEnd;
-
- private IFileUpload worker;
-
- #region KMP
-
- /// <summary>
- /// 构造 KMP 的匹配模式数组
- /// 对于 KMP 来说,函数表示包括当前字符的字串与整个模式串匹配的数量
- /// 0 表示当前位置无匹配
- ///
- /// </summary>
- /// <param name="pattern"></param>
- /// <returns></returns>
- private int[] BuildKMP(byte[] pattern)
- {
- int[] next = new int[pattern.Length];
-
- next[0] = 0;
- // 第一个位置一定为 0
-
- int j = 0;
- // 匹配的起始位置
- for (int i = 1; i < pattern.Length; i++)
- {
- // 如果已经匹配上,但是现在不能匹配,回溯寻找
- while (j > 0 && pattern[j] != pattern[i])
- {
- j = next[j - 1];
- }
-
- // 如果能够匹配上,向下推进一个位置
- // 注意 i 在 for 循环中自动推进
- if (pattern[j] == pattern[i])
- j++;
-
- // 保存
- next[i] = j;
- }
- return next;
- }
-
- #endregion
-
- public MultipartStream(IFileUpload worker, string boundaryString,
- int bufferSize)
- {
- boundaryString = "\r\n--" + boundaryString;
- this.boundary = System.Text.Encoding.ASCII.GetBytes(boundaryString);
- this.boundaryLength = boundary.Length;
- thisthis.next = this.BuildKMP(this.boundary);
-
- this.worker = worker;
-
- // 设置流的总长度
- this.length = worker.Length;
-
- // 预读
- this.startIndex = 0;
-
- // 缓冲区大小
- this.bufferLength =
- System.Math.Max(worker.PreloadLength, 64 * 1024);
-
- this.buffer = new byte[this.bufferLength];
- this.bufferStart = 0;
- this.bufferEnd = worker.GetPreloadedBody(this.buffer, 0);
- }
-
- // 是否允许读取
- public override bool CanRead
- {
- get { return true; }
- }
-
- // 是否允许定位
- public override bool CanSeek
- {
- get { return false; }
- }
-
- // 是否允许写入
- public override bool CanWrite
- {
- get { return false; }
- }
-
- public override void Flush()
- {
- throw new NotImplementedException();
- }
-
- public override int ReadByte()
- {
- // 是否已经读取到了最后
- if (this.startIndex + this.bufferStart >= this.length)
- return -1;
-
- // 希望读取的内容是否在缓冲区中
- if( this.bufferStart == this.bufferEnd)
- {
- // 已经超出边界,必须继续进行读取
- int count = this.MakeAvailable();
- }
- int result = this.buffer[this.bufferStart];
- this.bufferStart++;
-
- return result;
- }
|