官术网_书友最值得收藏!

2.3.8 Stream對象的用途

網絡上對Stream進行詳細講解的文章是不多的,很多文章只是一些屬性和方法的簡單列舉,更多的只是貼上一段代碼,然后告訴你這樣用就可以了。這樣是學不到東西的,遇到新問題的時候,仍然是不知所措。

前文講解的都是Stream操作的基礎知識,希望大家能夠多加練習,真正把它們弄透,達到隨心所欲的地步,因為Stream對象實在是太有用了。

下面就從用途的角度出發,進行一下整理。為了代碼的重復利用,這里使用Sub或Function的形式進行了封裝,所有方法都在StreamFunction.asp文件中。

(1)按指定的字符集讀取文件內容

Stream對象操作文本的一大優點就是它可以指定字符集,這是FSO無能為力的。讀取文件和保存文件的例子上面都說過,不再多說,直接看方法。

'filePath:文件物理路徑
'CharSet:文件的字符集
Function ReadTextFile(filePath, CharSet)
    Dim stream
    Set stream = Server.CreateObject("adodb.stream")
    stream.Type = 1                          '二進制方式
    stream.Open
    stream.LoadFromFile filePath             '載入文件
    stream.Type=2                            '文本方式
    stream.Charset = CharSet                 '設置字符集
    ReadTextFile = stream.ReadText           '讀取文本
    stream.Close
    Set stream = nothing
End Function

使用該方法時,需要事先知道文件使用的編碼,若設置錯誤的話,讀取到的文字將是亂碼。

(2)按指定的字符集保存內容到文件

對于Unicode編碼,前面我們都是直接使用“unicode”來指定的,它對應的其實就是Unicode Little Endian,前綴是“FF FE”。實際上,還有一個Unicode Big Endian,它的前綴是“FE FF”。想顯式指定,Unicode LE可以用“unicodeFFFE”, Unicode BE可以用“unicodeFEFF”。

這些前綴被稱為BOM(byte order mark),即字節順序標識。一些情況下,可能不想在文件開頭寫入BOM,可以通過數據流之間復制數據的辦法來跳過BOM。

看一下實現的方法。

'filePath:文件物理路徑
'fileContent:文件內容
'CharSet:文件的字符集
'isWriteBOM:是否寫入BOM
Sub WriteTextFile(filePath, fileContent, CharSet, isWriteBOM)
    Dim stream
    Set stream = Server.CreateObject("adodb.stream")
    stream.Type = 2 '文本方式
    stream.Charset = CharSet
    stream.Open
    stream.WriteText fileContent

    '如果是Unicode或UTF8,并且不寫入BOM,則特殊處理一下
    If instr("unicode|unicodefffe|unicodefeff|utf-8", Lcase(CharSet))>0 and NOT is WriteBOM Then
            '創建另外一個Stream對象
            Set streamNoBOM = Server.CreateObject("adodb.stream")

            streamNoBOM.Type = 1   '二進制方式
            streamNoBOM.Open

            '原Stream對象跳過BOM, UTF-8是3個字節,Unicode是2個字節
            If Lcase(CharSet)="utf-8" Then
                    stream.Position = 3
            Else
                    stream.Position = 2
            End If

            '復制數據
            stream.CopyTo streamNoBOM

            '寫入文件
            streamNoBOM.SaveToFile filePath,2      '文件存在則覆蓋

            streamNoBOM.Close
            set streamNoBOM = nothing
    Else
            stream.SaveToFile filePath,2           '文件存在則覆蓋
    End If
    stream.Close
    Set stream = nothing
End Sub

(3)編碼轉換

首先,請不要試圖在寫入數據后變更Charset來實現編碼轉換,那只是錯誤的讀取,并不是轉換。

Stream對象間進行數據復制的例子,實際就是一個編碼轉換的例子。這種轉換以Unicode為中介,將某種編碼的字符,轉換為另一種編碼中相同字形的字符。目標字符集中可能不存在對應的字符,所以轉換結果中可能存在問號(不存在的字符會以問號代替)。

要記住,目標編碼的數據只存在于Stream對象內,得到它的原型的最好辦法就是使用SaveToFile方法。所以,比較實用的一個轉換方式就是,讀入文件數據,變更編碼,寫回文件,從而實現文件編碼的轉換。當然,這種轉換只適用于GBK、Big5、Shift_JIS等編碼與Unicode或UTF-8之間的轉換,而不適用于Big5與Shift_JIS之間的轉換,因為二者不是包含關系,會有一些字符無法轉換。

其實想一想,你就會發現,只要調用前面提供的ReadTextFile()和WriteTextFile()兩個方法就能實現編碼轉換過程。所以,這里就不提供單獨的方法了。

(4)二進制數據轉換為文本

這里所說的二進制數據是指由文本轉換過去的,并不說任意的二進制數據都可以。把一個圖片的數據轉換為文本沒有什么意義,而且圖片數據中可能包含0x00這個字符(這個字符通常作為字符串的結束符),會影響文本的讀取。

看一下實現的方法。

'byteData:二進制數據
'CharSet:字符集
Function BinaryToText(byteData, CharSet)
    Dim stream
    Set stream = Server.CreateObject("ADODB.Stream")
    stream.Type = 1         '二進制方式
    stream.Open
    stream.Write byteData   '寫入二進制數據
    stream.Position = 0
    stream.Type = 2         '變更為文本方式
    stream.Charset = CharSet
    BinaryToText = stream.ReadText      '讀取文本
    stream.Close
    Set stream = nothing
End Function

(5)BSTR數據轉換為文本

由于Stream對象的Write方法要求參數必須是真正的字節數組,所以在BinaryToText()方法中直接傳入BSTR作為參數是不行的。那么,BSTR數據應該怎樣轉換為文本呢?下面就提供一種思路。

假設內存中有這樣一段BSTR數據,“E698A5E79CA0E4B88DE8A789E69993”,它是“春眠不覺曉”幾個字的UTF-8編碼形式。

首先,以字節為單位,將每個字節轉換為一個Unicode字符,那么“E6”將變為“E6 00”, “98”將變為“98 00”,以此類推,這些字符組成了新的字符串。然后,將此字符串寫入Stream對象,設定CharSet為“iso-8859-1”,那么將發生Unicode編碼到iso-8859-1編碼的轉換,“E6 00”變回了“E6”, “98 00”變回了“98”,以此類推。到此,我們已經將BSTR的數據寫入了Stream對象,剩下的工作就簡單了。將Stream對象的Charset變更為目標編碼,這里設置為“UTF-8”,然后讀取文本即可。

那么,為什么第二步中CharSet要使用“iso-8859-1”呢,因為它在128~255這個范圍內有字符定義(因為BSTR數據可能包含漢字,所以一個字節可能大于128)。這一步如果使用ASCII、GBK或Big5等編碼是不行的,這些編碼在128~255范圍內都沒有字符定義,轉換后字符會變成問號。

下面看一下范例。

BSTR2Text.asp

<%@codepage=936%>
<%
Response.Charset = "GBK"
'十六進制數據
Dim hexStr, bstr
hexStr = "E698A5E79CA0E4B88DE8A789E69993"

'拼接BSTR數據
For i=1 To Len(hexStr) Step 2
    bstr = bstr & ChrB("&H" & Mid(hexStr, i,2))
Next
response.write "BSTR的數據:" & getMemoryFormat(bstr) & "<br>"

'進行轉換
result = bstr2Text(bstr, "UTF-8")

'輸出轉換結果
response.write result

'---------------BSTR轉換為文本------------------------
'bstr:BSTR數據
'targetCharset:目標字符集
Function bstr2Text(bstr, targetCharset)

    '首先將BSTR數據轉換為字符串。
    Dim str
    str = ""
    For i = 1 To LenB(bstr)
            '將每個字節的數據轉換為兩個字節的字符。如E6將變為E6 00
            '一定要使用ChrW(),不要使用Chr(),后者受當前CodePage影響
            str = str & chrw(AscB(MidB(bstr, i,1)))
    Next
    response.write "內存的數據:" & getMemoryFormat(str) & "<br>"

    '將字符串寫入Stream對象,實現Unicode到ISO 8859-1的轉換
    Dim stream
    Set stream = Server.CreateObject("adodb.stream")
    stream.Type = 2 '文本方式
    stream.Charset = "iso-8859-1"          '字符集使用ISO 8859-1
    stream.Open
    stream.WriteText str

    '打印Stream對象中的數據
    Call printStream(stream)

    'Stream對象中的數據,已經是我們想要的二進制形式了,可以讀取了
    stream.Position=0
    stream.Charset = targetCharset         '按指定編碼讀取文本
    bstr2Text = stream.ReadText
    stream.Close
    Set stream = nothing
End Function
%>

運行結果如圖2-27所示。

圖2-27 BSTR轉換為文本

(6)文本轉換為二進制數據

文本轉換為二進制數據很簡單,寫入文本,按二進制方式讀取即可。Charset為Unicode或UTF-8時,會自動加入2個或3個字節的前綴。如果不需要它們,則讀取時應該跳過,以下的范例是跳過前綴的。

'textData:文本數據
'CharSet:字符集
Function TextToBinary(textData, CharSet)
    Dim stream
    Set stream = Server.CreateObject("ADODB.Stream")
    stream.Type = 2                 '文本方式
    stream.Charset = CharSet
    stream.Open
    stream.WriteText textData       '寫入文本數據
    stream.Position = 0
    stream.Type = 1                 '二進制方式
    If UCase(CharSet) = "UTF-8" Then
            stream.Position= 3      '跳過3個字節的前綴
    ElseIf UCase(CharSet) = "UNICODE" Then
            stream.Position= 2      '跳過2個字節
    End If
    TextToBinary = stream.Read      '讀取二進制數據
    stream.Close
    Set stream = nothing
End Function

(7)讀取文件的二進制數據

在文件下載的系統中,通常需要用到此功能。使用Stream對象讀入文件的數據,然后使用Response對象的BinaryWrite方法輸出給客戶端。

'filePath:文件物理路徑
Function LoadFileContent(filePath)
    Dim stream
    Set stream = Server.CreateObject("adodb.stream")
    stream.Type = 1                    '二進制方式
    stream.Open
    stream.LoadFromFile filePath
    LoadFileContent = stream.Read      '讀取文件內容
    stream.Close
    Set stream = nothing
End Function

(8)二進制數據保存到文件

此功能的用途是很廣泛的,如將接收到的Request數據、XMLHttp遠程取得的數據或數據庫的文件數據等二進制數據保存到文件。

'---------------寫入文件------------------------
'filePath:文件物理路徑
'byteData:二進制數據
Sub WriteToFile(filePath, byteData)
    Dim stream
    Set stream = Server.CreateObject("adodb.stream")
    stream.Type = 1                   '二進制方式
    stream.Open
    stream.Write byteData
    stream.SaveToFile filePath,2      '文件存在則覆蓋
    stream.Close
    Set stream = nothing
End Sub
主站蜘蛛池模板: 林口县| 耿马| 甘德县| 神木县| 阿城市| 屏山县| 嘉峪关市| 邢台市| 沁水县| 柳河县| 长垣县| 汤阴县| 新邵县| 凤山县| 县级市| 洪江市| 东乡县| 辽源市| 积石山| 江陵县| 定远县| 晋城| 安西县| 简阳市| 桦甸市| 塔城市| 浏阳市| 阿拉善右旗| 盘锦市| 广丰县| 桑日县| 庄河市| 嵊泗县| 南投市| 平潭县| 大英县| 盐池县| 绥滨县| 申扎县| 衡南县| 民勤县|