分享

读取上传数据流(1)

 悟静 2012-02-16

读取上传数据流(1)

在 POST 方式的请求中,请求参数通过请求的 Body 部分提供,在多部分形式的请求中,通过边界来划分请求参数。在这一部分的代码中,主要是计算好边界的位置。为了便于读取上传的文件,MultipartStream 流专门用于读取多部分组成的数据,如代码清单2-7所示。

代码清单2-7 读取上传数据流

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.  
  6. using System.IO;  
  7. using System.Web;  
  8. using System.Text.RegularExpressions;  
  9.  
  10. namespace DiskFileUpload  
  11. {  
  12.     public class MultipartStream : Stream  
  13.     {  
  14.         private System.Text.Encoding bodyEncoding =
    System.Text.Encoding.UTF8;  
  15.  
  16.         private static int HEADER_PART_SIZE_MAX = 4096;  
  17.  
  18.         private static byte[] HEADER_SEPARATOR = 
    new byte[] { 0xd, 0xa, 0xd, 0xa };  
  19.  
  20.         // 匹配参数名称的正则表达式 . 表示除换行之外的所有字符  
  21.         // +? 表示懒惰模式  
  22.         private static readonly System.Text.
    RegularExpressions.Regex 
    nameRegex 
  23.             = new System.Text.RegularExpressions.
    Regex("
    name=\"(.+?)\"");  
  24.  
  25.         // 匹配上传文件名的正则表达式  
  26.         private static readonly System.Text.
    RegularExpressions.Regex 
    filenameRegex 
  27.             = new System.Text.RegularExpressions.
    Regex("
    filename=\"(.+)\"");  
  28.  
  29.         private static readonly System.Text.
    RegularExpressions.Regex 
    contentTypeRegex 
  30.             = new Regex("Content-Type=\"(.+)\"");  
  31.  
  32.         private byte[] boundary;  
  33.         private int boundaryLength;  
  34.  
  35.         int[] next;  
  36.  
  37.         // 流中内容的字节长度  
  38.         private long length;  
  39.         public override long Length  
  40.         {  
  41.             get { return this.length; }  
  42.         }  
  43.  
  44.         // 当前位置  
  45.         public override long Position  
  46.         {  
  47.             get { return this.startIndex + this.bufferStart; }  
  48.             set { throw new Exception("不允许设置当前位置"); }  
  49.         }  
  50.  
  51.         // 内部预读的缓冲区  
  52.         private byte[] buffer;  
  53.  
  54.         // 缓冲内容的起始位置  
  55.         private int startIndex;  
  56.         private int bufferLength;  
  57.  
  58.         // 缓冲区也不一定填满,缓冲区有内容部分的起始下标  
  59.         private int bufferStart;  
  60.         private int bufferEnd;  
  61.  
  62.         private IFileUpload worker;  
  63.  
  64.         #region KMP  
  65.  
  66.         /// <summary> 
  67.         /// 构造 KMP 的匹配模式数组  
  68.         /// 对于 KMP 来说,函数表示包括当前字符的字串与整个模式串匹配的数量  
  69.         /// 0 表示当前位置无匹配  
  70.         ///  
  71.         /// </summary> 
  72.         /// <param name="pattern"></param> 
  73.         /// <returns></returns> 
  74.         private int[] BuildKMP(byte[] pattern)  
  75.         {  
  76.             int[] next = new int[pattern.Length];  
  77.  
  78.             next[0] = 0;  
  79.  // 第一个位置一定为 0  
  80.  
  81.             int j = 0;  
  82.  // 匹配的起始位置  
  83.             for (int i = 1; i < pattern.Length; i++)  
  84.             {  
  85.                 // 如果已经匹配上,但是现在不能匹配,回溯寻找  
  86.                 while (j > 0 && pattern[j] != pattern[i])  
  87.                 {  
  88.                     j = next[j - 1];  
  89.                 }  
  90.  
  91.                 // 如果能够匹配上,向下推进一个位置  
  92.                 // 注意 i 在 for 循环中自动推进  
  93.                 if (pattern[j] == pattern[i])  
  94.                     j++;  
  95.  
  96.                 // 保存  
  97.                 next[i] = j;  
  98.             }  
  99.             return next;  
  100.         }  
  101.  
  102.         #endregion  
  103.  
  104.         public MultipartStream(IFileUpload worker, string boundaryString,  
  105.             int bufferSize)  
  106.         {  
  107.             boundaryString = "\r\n--" + boundaryString;  
  108.             this.boundary = System.Text.Encoding.ASCII.GetBytes(boundaryString);  
  109.             this.boundaryLength = boundary.Length;  
  110.             thisthis.next = this.BuildKMP(this.boundary);  
  111.  
  112.             this.worker = worker;  
  113.  
  114.             // 设置流的总长度  
  115.             this.length = worker.Length;  
  116.  
  117.             // 预读  
  118.             this.startIndex = 0;  
  119.  
  120.             // 缓冲区大小  
  121.             this.bufferLength =  
  122.                 System.Math.Max(worker.PreloadLength, 64 * 1024);  
  123.  
  124.             this.buffer = new byte[this.bufferLength];  
  125.             this.bufferStart = 0;  
  126.             this.bufferEnd = worker.GetPreloadedBody(this.buffer, 0);  
  127.         }  
  128.  
  129.         // 是否允许读取  
  130.         public override bool CanRead  
  131.         {  
  132.             get { return true; }  
  133.         }  
  134.  
  135.         // 是否允许定位  
  136.         public override bool CanSeek  
  137.         {  
  138.             get { return false; }  
  139.         }  
  140.  
  141.         // 是否允许写入  
  142.         public override bool CanWrite  
  143.         {  
  144.             get { return false; }  
  145.         }  
  146.  
  147.         public override void Flush()  
  148.         {  
  149.             throw new NotImplementedException();  
  150.         }  
  151.  
  152.         public override int ReadByte()  
  153.         {  
  154.             // 是否已经读取到了最后  
  155.             if (this.startIndex + this.bufferStart >= this.length)  
  156.                 return -1;  
  157.  
  158.             // 希望读取的内容是否在缓冲区中  
  159.             if( this.bufferStart == this.bufferEnd)  
  160.             {  
  161.                 // 已经超出边界,必须继续进行读取  
  162.                 int count = this.MakeAvailable();  
  163.             }  
  164.             int result =  this.buffer[this.bufferStart];  
  165.             this.bufferStart++;  
  166.  
  167.             return result;  
  168.         } 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约