- 深入解析ASP核心技術
- 王洪影
- 2448字
- 2019-01-03 18:16:04
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