2012年7月30日 星期一

System.IO.StreamReader/StreamWriter 和 System.IO.File.ReadAllText/WriteAllText

我在「利用StreamWriter 資料流I/O 寫成檔案」這篇文章寫了一個自已學習的歷程
主題雖然是使用System.IO類別下的方法,但是具體而微,System.IO命名空間下,除了有提供讀寫檔案和資料流的類別外,就是基本檔案、目錄管理的類別。方法都是大同小異…

這次的程式碼範例,我就特別針對「將內容寫進新建的文字檔」「開啟檔案並讀取內容」「將內容附加到既有的文字檔」這三個功能,分別寫了System.IO.Stream 和System.IO.File 二種版本,用這二種類別都可以完成,邏輯上是一樣的,只不過要使用自已類別下的Method方法來達成目的而已。

頁面上的佈置很簡單,一個TextBox、三顆功能按鈕

以下提供File和Stream二種類別的寫法

使用System.IO.StreamReader / StreamWriter 的寫法

Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Me.ButtonIOWirte.Text = "將內容寫進新建的文字檔"
        Me.ButtonIORead.Text = "開啟檔案並讀取內容"
        Me.ButtonIOAppend.Text = "將內容附加到既有的文字檔"
    End Sub
    Protected Sub ButtonIOWirte_Click(sender As Object, e As System.EventArgs) Handles ButtonIOWirte.Click
        FileManager.CreateTextFile(Page, Server.MapPath("DnowLog/AspNet51.txt"), Me.TextBoxIO.Text)
    End Sub
    Protected Sub ButtonIORead_Click(sender As Object, e As System.EventArgs) Handles ButtonIORead.Click
        FileManager.OpenFileRead(Page, MapPath("DnowLog/AspNet51.txt"))
    End Sub
    Protected Sub ButtonIOAppend_Click(sender As Object, e As System.EventArgs) Handles ButtonIOAppend.Click
        FileManager.CreatTextAppend(Page, MapPath("DnowLog/AspNet51.txt"), Me.TextBoxIO.Text)
    End Sub

MSDN****************************************************  
        'http://msdn.microsoft.com/zh-tw/library/system.io.file.aspx (建立文字檔 System.IO.File)
        '***************************************************************************************
        Public Shared Sub CreateTextFile(ByVal WebForm As System.Web.UI.Page, ByVal path As String, ByVal filebody As String)
            If System.IO.File.Exists(path) = False Then
                'Using sw As System.IO.StreamWriter = System.IO.File.CreateText(path)
                Using sw As New System.IO.StreamWriter(path, True)
                    sw.Write(filebody)
                    sw.Flush()
                End Using
            End If
        End Sub

        ' 開啟檔案並讀取內容 參考自MSDN*********************************************************  
        ' http://msdn.microsoft.com/zh-tw/library/system.io.file.aspx (建立文字檔 System.IO.File)
        ' http://msdn.microsoft.com/zh-tw/library/db5x7c0d.aspx (讀取文字檔 HOW TO:從檔案讀取文字)
        ' ******************************************************************************************
        Public Shared Sub OpenFileRead(ByVal WebForm As System.Web.UI.Page, ByVal path As String)
            Try
                Using sr As System.IO.StreamReader = System.IO.File.OpenText(path)
                    ' 第一種讀取內容的方法=============================================
                    'Dim sb As New StringBuilder()
                    'sb.AppendLine(sr.ReadToEnd)
                    'CType(WebForm.FindControl("TextBox1"), TextBox).Text = sb.ToString
                    '===================================================================

                    ' 第二種讀取內容的方法============================================
                    'Dim sb As New StringBuilder()
                    'Do While sr.Peek() >= 0
                    '    sb.AppendLine(sr.ReadLine())
                    'Loop
                    'CType(WebForm.FindControl("TextBox1"), TextBox).Text = sb.ToString
                    '==================================================================

                    ' 第三種讀取內容的方法=============================================
                    Dim sb As New StringBuilder()
                    Dim line As String
                    Do
                        line = sr.ReadLine()
                        If line IsNot Nothing Then
                            sb.AppendLine(line)
                        End If
                    Loop Until line Is Nothing
                    CType(WebForm.FindControl("TextBoxIO"), TextBox).Text = sb.ToString
                    '===================================================================
                End Using
            Catch e As Exception
                CType(WebForm.FindControl("TextBoxIO"), TextBox).Text = e.Message & "無法開啟指定檔案,或是無法正確讀取檔案內容,請洽詢管理員"
            End Try
        End Sub
        ' 將內容附加到既有的文字檔,參考自**************************************************************** 
        ' http://msdn.microsoft.com/zh-tw/library/3zc0w663.aspx (HOW TO:開啟並附加至記錄檔)
        ' *******************************************************************************************
        Public Shared Sub CreatTextAppend(ByVal WebForm As System.Web.UI.Page, ByVal path As String, ByVal filebodyappend As String)
            Using sw As New System.IO.StreamWriter(path, True)
                sw.WriteLine(filebodyappend)
            End Using
        End Sub
    End Class

使用System.IO.File.ReadAllText / WriteAllText 的寫法

    Protected Sub Page_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Me.ButtonIOWirte.Text = "將內容寫進新建的文字檔"
        Me.ButtonIORead.Text = "開啟檔案並讀取內容"
        Me.ButtonIOAppend.Text = "將內容附加到既有的文字檔"
    End Sub
    Protected Sub ButtonIOWirte_Click(sender As Object, e As System.EventArgs) Handles ButtonIOWirte.Click
        FileManager.CreateTextFile(Page, Server.MapPath("DnowLog/AspNet52.txt"), Me.TextBoxIO.Text)
    End Sub
    Protected Sub ButtonIORead_Click(sender As Object, e As System.EventArgs) Handles ButtonIORead.Click
        FileManager.OpenFileRead(Page, MapPath("DnowLog/AspNet52.txt"))
    End Sub

    Protected Sub ButtonIOAppend_Click(sender As Object, e As System.EventArgs) Handles ButtonIOAppend.Click
        FileManager.CreatTextAppend(Page, MapPath("DnowLog/AspNet52.txt"), Me.TextBoxIO.Text)
    End Sub
    Public Class FileManager
        ' 將文字寫進新建的文字檔 參考自MSDN****************************************************  
        'http://msdn.microsoft.com/zh-tw/library/ms143368.aspx (File.ReadAllText 方法)
        '***************************************************************************************
        Public Shared Sub CreateTextFile(ByVal WebForm As System.Web.UI.Page, ByVal path As String, ByVal filebody As String)
            If System.IO.File.Exists(path) = False Then
                System.IO.File.WriteAllText(path, filebody)
            End If
        End Sub

        ' 開啟檔案並讀取內容 參考自MSDN*********************************************************  
        'http://msdn.microsoft.com/zh-tw/library/ms143368.aspx (File.ReadAllText 方法)
        ' ******************************************************************************************
        Public Shared Sub OpenFileRead(ByVal WebForm As System.Web.UI.Page, ByVal path As String)
            Try
                CType(WebForm.FindControl("TextBoxIO"), TextBox).Text = System.IO.File.ReadAllText(path)
            Catch e As Exception
                CType(WebForm.FindControl("TextBoxIO"), TextBox).Text = e.Message & "無法開啟指定檔案,或是無法正確讀取檔案內容,請洽詢管理員"
            End Try
        End Sub
        ' 將內容附加到既有的文字檔,參考自**************************************************************** 
        ' http://msdn.microsoft.com/zh-tw/library/3zc0w663.aspx (HOW TO:開啟並附加至記錄檔)
        ' *******************************************************************************************
        Public Shared Sub CreatTextAppend(ByVal WebForm As System.Web.UI.Page, ByVal path As String, ByVal filebodyappend As String)
            System.IO.File.AppendAllText(path, Environment.NewLine & filebodyappend)
        End Sub
    End Class
End Class

在完成一個功能的使用,有時候開發時間所限
我們需要先求有再求好,在最短的時間內達到目的
這篇文章是已經有要求更好,主要是在研究

這篇文章主要就是在討論
System.IO.StreamReader/StreamWriter 和 System.IO.File.ReadAllText/WriteAllText
既然都可以完成一樣的功能
那麼為什麼不整合在一起就好了
二者之間有沒有什麼不一樣

 

我想就我自已實作後分享一下兩者之間的不同

 

1、二者的類別不同

如下圖,以StreamReader/ReadAllText 來看
StreamReader/StreamWriter 本身是類別
ReadAllText/WriteAllText 是System.IO.File下的方法
所以很明顯的二者的類別不同…廢話

這樣的差別就可以概略知道,一定是架構大一點的或是有特定目的之下才會「自成一類」,可以猜的到單就「存取檔案」的功能來說,身為類別的「StreamReader/StreamWriter 」肩負著比較多的功能。

比方說,我要把資料寫入一個檔案,寫入前要先檢查檔案是否存在
System.IO.StreamWriter 的寫法,用自已類別下的方法可以解決:
   Using sw As New System.IO.StreamWriter( "C:/Document/Dnowba.txt" , True)
      sw.Write( "這是測試文字" )
   End Using

System.IO.File.WriteAllText 的寫法可能就要用到「其他的方法」:
    If System.IO.File.Exists( "C:/Document/Dnowba.txt" ) = False Then
       System.IO.File.WriteAllText("C:/Document/Dnowba.txt", "這是測試文字")
    End If

那麼也許我們可以說System.IO.StreamWriter 和 System.IO.File.WriteAllText 在「功能」上並沒有什麼差異。StreamWriter 不過是包裝比較精美的程式。是不是這樣呢?也許我們再從實作上觀察一下…

我們在呼叫方法之後,觀察一下他們就方法來說的話,WriteAllText 的方法多載(overload,又叫重載、覆載) 有二種。

但是在StreamWriter上的方法多載數量高達17個

你說包裝精不精美?System.IO.StreamReader/StreamWriter 在檔案存取的應用上應當是可以更靈活富變化。
不過我們也可以看到System.IO.File 底下是有其他的方法的,雖然不一定是針對檔案存取功能…但其他功能的支援性是比較足的。

所以在檔案存取時,用哪個方法比較好?沒有一定。
如果你要針對檔案內容做比較複雜的運用的話,用System.IO.StreamWriter
如果你只是簡單的使用 (像上面) ,那麼用System.IO.File.WriteAllText 就措措有餘

我再舉個例子說明…
System.IO.StreamWriter 的寫法,多載的方法下提供了可以format string的參數:
   Using sw As New System.IO.StreamWriter( "C:/Document/Dnowba.txt" , True)
      sw.Write( "本文章作者{0},發佈日期{1}","DNOWBA",DateTime.Now )
   End Using

System.IO.File.WriteAllText 下要把字串格式化,就只能透過最原始的串接:
    If System.IO.File.Exists( "C:/Document/Dnowba.txt" ) = False Then
       System.IO.File.WriteAllText("C:/Document/Dnowba.txt", "本文作者DNOWBA,
                                                      發佈日期" & DateTime.Now )
    End If

2 、 類別宣告方式不同

System.IO.StreamReader/StreamWriter 是Instance Class
System.IO.File 是 Static Class…

所以在 System.IO.StreamReader/StreamWriter 使用時都需要「實體化」
image

而靜態類別的成員則不需要透過類別的執行個體就可以直接存取
image

靜態宣告和非靜態宣告的差別當然不只這樣
最常被討論是用靜態宣告和非靜態宣告的效能上的差別

靜態宣告在一載入程式時,整個class就會被加載到執行緒
非靜態宣告只有當你「new」的時候才會生效,而變數使用完畢後就可以丟掉
效能問題不是我這個後生小輩可以討論的
不過看起來的確是靜態宣告比較耗費資源
所以用非靜態宣告的System.IO.StreamReader/StreamWriter 比較好?其實這也沒有一定
如果你在這個webform主要的功能就是讀寫檔案,需要不斷不斷的使用的話,那麼開開關關的的非靜態宣告方式就很沒有必要,資源在開關之間也是會消耗的。

3、應用時機不同

我在使用Framework的時候,常常會發現在裡頭有很多類似的情形
「二個函式都可以完成某種特定功能,為什麼不要合併在一起呢?」
我覺得可以合理懷疑一件事
Framework 是一個巨大的架構,架構設計師應該不只一位,包括架構師在內,在不同架構師底下的團隊也不大可能每個人都對Framework 都瞭若指掌,再加上開發的時間點不一致的情況下,那麼

會不會在開發 System.IO.File 類別下有關檔案讀取功能的時候,架構師渾然不知Framework 裡早就有很棒的System.IO.StreamReader/StreamWriter 呢?
(我覺得這個可能性很大…)

如果已經知道有 System.IO.StreamReader/StreamWriter ,會不會在開發 System.IO.File 下的檔案讀取功能時,偷偷的用了 System.IO.StreamReader/StreamWriter ?
( 如果我能打開它的.dll 組態設定檔,也許就能查證了)

不過前面提到了他們在不同類別底下
同母(Framework)異父(Class) 的情況下,當然長相 (方法) 也還是有分別,對我來說:

檔案的應用在程式設計上是重點:
在WinForm程式偏重在檔案的管理,例如對檔案的刪除、複製、移動。
在WebForm上則偏重在讀取後匯入、寫進後匯出檔案的功能。


偶有所得

這一次的程式碼中是在研究中誕生
本來是範例是直接寫在事件常式中
寫著寫著,覺得二者之間互有異同
所以就嘗試使用自訂類別
讓程式間能夠互通有無
我想這也是寫程式的人最想要完成的一件事

1、在webform裡完成某個功能 用不同的變數/方法,寫在各自的事件常式中
2、在同一個webform互相調用 用Function 或 Sub副程式,把可以共用的程式整合,讓其他事件常式可以反覆調用
3、同一個網站的webform 集結了許多的Function 或 Sub副程式後,再把共用的功能包成不同或同一個Class,讓專案中的其他webform引用
4、不同網站/專案 把class編譯成DLL檔,可以將這個.net檔「加入參考」
5、分散式的網站 透過Web Service 或是 WCF

這次的程式碼就是在第2階段啦
雖然有點生硬,不過還算堪用
分享給大家。

沒有留言:

張貼留言

Related Posts Plugin for WordPress, Blogger...
// Dnow Function