天天看點

[C#]Stream.Write Extension Method

在處理Stream型态時常會使用到Stream.Write這個方法,每次都會有種疑問就是,大多數的處理都是要将Buffer整個寫入,為何偏偏每次都要将索引帶0,長度帶為Buffer的大小呢?另外在處理Stream時,若要顯示其處理進度,是否能有更為簡單的方法?這邊将我為了解決這些問題所寫的擴充方法整裡如下:

<code>using</code> <code>System;</code>

<code>02</code>

<code>using</code> <code>System.Reflection;</code>

<code>03</code>

<code>using</code> <code>System.ComponentModel;</code>

<code>04</code>

<code>using</code> <code>System.Linq;</code>

<code>05</code>

<code>using</code> <code>System.IO;</code>

<code>06</code>

<code>07</code>

<code>public</code> <code>static</code> <code>class</code> <code>StreamExtension</code>

<code>08</code>

<code>{</code>

<code>09</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>Write(</code><code>this</code> <code>Stream targetStream,</code><code>byte</code><code>[] buffer)</code>

<code>10</code>

<code>    </code><code>{</code>

<code>11</code>

<code>        </code><code>if</code> <code>(!targetStream.CanWrite)</code>

<code>12</code>

<code>            </code><code>throw</code> <code>new</code> <code>ArgumentException(</code><code>"targetStream"</code><code>,</code><code>"Unwritable stream"</code><code>);</code>

<code>13</code>

<code>14</code>

<code>        </code><code>targetStream.Write(buffer, 0, buffer.Length);</code>

<code>15</code>

<code>    </code><code>}</code>

<code>16</code>

<code>17</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>Write(</code><code>this</code> <code>Stream targetStream, Stream sourceStream)</code>

<code>18</code>

<code>19</code>

<code>20</code>

<code>21</code>

<code>22</code>

<code>        </code><code>if</code> <code>(sourceStream ==</code><code>null</code><code>)</code>

<code>23</code>

<code>            </code><code>throw</code> <code>new</code> <code>ArgumentNullException(</code><code>"sourceStream"</code><code>);</code>

<code>24</code>

<code>25</code>

<code>        </code><code>if</code> <code>(!sourceStream.CanRead)</code>

<code>26</code>

<code>            </code><code>throw</code> <code>new</code> <code>ArgumentException(</code><code>"sourceStream"</code><code>,</code><code>"Unreadable stream"</code><code>);</code>

<code>27</code>

<code>28</code>

<code>        </code><code>targetStream.Write(sourceStream, 1024,</code><code>null</code><code>);</code>

<code>29</code>

<code>30</code>

<code>31</code>

<code>    </code><code>public</code> <code>static</code> <code>void</code> <code>Write(</code><code>this</code> <code>Stream targetStream, Stream sourceStream,</code><code>int</code> <code>bufferSize, Action&lt;</code><code>object</code><code>, System.ComponentModel.ProgressChangedEventArgs&gt; progressChangedCallBack)</code>

<code>32</code>

<code>33</code>

<code>34</code>

<code>35</code>

<code>36</code>

<code>37</code>

<code>38</code>

<code>39</code>

<code>40</code>

<code>41</code>

<code>42</code>

<code>        </code><code>if</code> <code>(bufferSize &lt; 1024)</code>

<code>43</code>

<code>            </code><code>throw</code> <code>new</code> <code>ArgumentOutOfRangeException(</code><code>"bufferSize"</code><code>,</code><code>"Must bigger than 1024"</code><code>);</code>

<code>44</code>

<code>45</code>

<code>        </code><code>byte</code><code>[] buffer =</code><code>new</code> <code>byte</code><code>[bufferSize];</code>

<code>46</code>

<code>47</code>

<code>        </code><code>int</code> <code>offset = 0;</code>

<code>48</code>

<code>        </code><code>int</code> <code>readByteCount = 0;</code>

<code>49</code>

<code>        </code><code>int</code> <code>percent = 0;</code>

<code>50</code>

<code>51</code>

<code>        </code><code>while</code> <code>((readByteCount = sourceStream.Read(buffer, 0, bufferSize)) &gt; 0)</code>

<code>52</code>

<code>        </code><code>{</code>

<code>53</code>

<code>            </code><code>targetStream.Write(buffer, 0, readByteCount);</code>

<code>54</code>

<code>55</code>

<code>            </code><code>if</code> <code>(progressChangedCallBack !=</code><code>null</code><code>)</code>

<code>56</code>

<code>            </code><code>{</code>

<code>57</code>

<code>                </code><code>offset += readByteCount;</code>

<code>58</code>

<code>59</code>

<code>                </code><code>var currentPercent = (</code><code>int</code><code>)(((</code><code>double</code><code>)offset) / sourceStream.Length * 100);</code>

<code>60</code>

<code>                </code><code>if</code> <code>(currentPercent == percent)</code>

<code>61</code>

<code>                    </code><code>continue</code><code>;</code>

<code>62</code>

<code>63</code>

<code>                </code><code>percent = currentPercent;</code>

<code>64</code>

<code>                </code><code>progressChangedCallBack(targetStream,</code><code>new</code> <code>System.ComponentModel.ProgressChangedEventArgs(percent,</code><code>null</code><code>));</code>

<code>65</code>

<code>            </code><code>}</code>

<code>66</code>

<code>        </code><code>}</code>

<code>67</code>

<code>68</code>

<code>}</code>

使用上Write方法會多三個多載版本,一個是將buffer整個寫入、一個是將stream的內容整個讀出並寫入、一個則是用來寫入整個stream內容,並可帶入處理的Buffer大小,與處理進度回報的Callback,用以處理進度的顯示。

<a href="http://www.dotblogs.com.tw/larrynung/archive/2011/07/12/31519.aspx#viewSource">view source</a>

<code>1</code>

<code>targetStream.Write(buffer);</code>

<code>2</code>

<code>targetStream.Write(sourceStream);</code>

<code>3</code>

<code>targetStream.Write(sourceStream, 1024, (sender, e) =&gt; { Console.WriteLine(e.ProgressPercentage.ToString ()); });</code>

這邊針對進度處理的擴充方法示範個較為詳細的範例,這邊我會讀取C槽下的test.data檔案,檔案大小為5MB多,開啟後將其寫入c槽下的test_copy.data。處理的buffer大小為1024,每當在處理時偵測到進度改變時會顯示出當前處理的進度比例。

<code>01</code>

<code>using</code> <code>System.Collections.Generic;</code>

<code>using</code> <code>System.Text;</code>

<code>namespace</code> <code>ConsoleApplication11</code>

<code>    </code><code>class</code> <code>Program</code>

<code>        </code><code>static</code> <code>void</code> <code>Main(</code><code>string</code><code>[] args)</code>

<code>        </code><code>{           </code>

<code>                </code><code>using</code> <code>(FileStream targetStream = File .Create (</code><code>@"c:\test_copy.dat"</code><code>))</code>

<code>                </code><code>{</code>

<code>                    </code><code>using</code> <code>(FileStream sourceStream= File.Open (</code><code>@"c:\test.dat"</code><code>, FileMode.Open))</code>

<code>                    </code><code>{</code>

<code>                        </code><code>targetStream.Write(sourceStream, 1024, (sender, e) =&gt; { Console.WriteLine(e.ProgressPercentage.ToString()); });</code>

<code>                    </code><code>}</code>

<code>                </code><code>}</code>

運行結果如下:

<a href="http://files.dotblogs.com.tw/larrynung/1107/CExtensionMethodStr.WriteExtensionMethod_13D5C/image_2.png"></a>