在處理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<</code><code>object</code><code>, System.ComponentModel.ProgressChangedEventArgs> 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 < 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)) > 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) => { 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) => { 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>