讀取上傳數(shù)據(jù)流(1)
在 POST 方式的請求中,請求參數(shù)通過請求的 Body 部分提供,在多部分形式的請求中,通過邊界來劃分請求參數(shù)。在這一部分的代碼中,主要是計算好邊界的位置。為了便于讀取上傳的文件,MultipartStream 流專門用于讀取多部分組成的數(shù)據(jù),如代碼清單2-7所示。
代碼清單2-7 讀取上傳數(shù)據(jù)流 - 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 }; -
- // 匹配參數(shù)名稱的正則表達(dá)式 . 表示除換行之外的所有字符
- // +? 表示懶惰模式
- private static readonly System.Text.
RegularExpressions.Regex nameRegex - = new System.Text.RegularExpressions.
Regex("name=\"(.+?)\""); -
- // 匹配上傳文件名的正則表達(dá)式
- 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;
-
- // 流中內(nèi)容的字節(jié)長度
- private long length;
- public override long Length
- {
- get { return this.length; }
- }
-
- // 當(dāng)前位置
- public override long Position
- {
- get { return this.startIndex + this.bufferStart; }
- set { throw new Exception("不允許設(shè)置當(dāng)前位置"); }
- }
-
- // 內(nèi)部預(yù)讀的緩沖區(qū)
- private byte[] buffer;
-
- // 緩沖內(nèi)容的起始位置
- private int startIndex;
- private int bufferLength;
-
- // 緩沖區(qū)也不一定填滿,緩沖區(qū)有內(nèi)容部分的起始下標(biāo)
- private int bufferStart;
- private int bufferEnd;
-
- private IFileUpload worker;
-
- #region KMP
-
- /// <summary>
- /// 構(gòu)造 KMP 的匹配模式數(shù)組
- /// 對于 KMP 來說,函數(shù)表示包括當(dāng)前字符的字串與整個模式串匹配的數(shù)量
- /// 0 表示當(dāng)前位置無匹配
- ///
- /// </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++)
- {
- // 如果已經(jīng)匹配上,但是現(xiàn)在不能匹配,回溯尋找
- while (j > 0 && pattern[j] != pattern[i])
- {
- j = next[j - 1];
- }
-
- // 如果能夠匹配上,向下推進(jìn)一個位置
- // 注意 i 在 for 循環(huán)中自動推進(jìn)
- 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;
-
- // 設(shè)置流的總長度
- this.length = worker.Length;
-
- // 預(yù)讀
- this.startIndex = 0;
-
- // 緩沖區(qū)大小
- 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()
- {
- // 是否已經(jīng)讀取到了最后
- if (this.startIndex + this.bufferStart >= this.length)
- return -1;
-
- // 希望讀取的內(nèi)容是否在緩沖區(qū)中
- if( this.bufferStart == this.bufferEnd)
- {
- // 已經(jīng)超出邊界,必須繼續(xù)進(jìn)行讀取
- int count = this.MakeAvailable();
- }
- int result = this.buffer[this.bufferStart];
- this.bufferStart++;
-
- return result;
- }
|