给string增加一个GetInputStream扩展方法
有时候,我们需要读取一些数据,而不管这数据来源于磁盘上的数据文件,还是来源于网络上的数据。于是,就有了下面的StringExtensions.cs:
复制代码
1usingSystem;
2usingSystem.IO;
3usingSystem.Net;
4
5namespaceSkyiv
6{
7publicstaticclassStringExtensions
8{
9publicstaticStreamGetInputStream(thisstringfileNameOrUri,stringuser=null,stringpassword=null)
10{
11if(!Uri.IsWellFormedUriString(fileNameOrUri,UriKind.Absolute))returnFile.OpenRead(fileNameOrUri);
12varuri=newUri(fileNameOrUri);
13if(uri.Scheme==Uri.UriSchemeHttp||uri.Scheme==Uri.UriSchemeHttps)returnuri.GetHttpStream();
14if(uri.Scheme==Uri.UriSchemeFtp)returnuri.GetFtpStream(user,password);
15if(uri.Scheme==Uri.UriSchemeFile)returnuri.GetFileStream();
16thrownewNotSupportedException("Notsupportedurischeme:"+uri.Scheme);
17}
18
19staticStreamGetFtpStream(thisUriuri,stringuser=null,stringpassword=null)
20{
21varftp=(FtpWebRequest)WebRequest.Create(uri);
22if(user!=null&&user!="anonymous"&&user!="ftp")
23ftp.Credentials=newNetworkCredential(user,password);
24ftp.Method=WebRequestMethods.Ftp.DownloadFile;
25return((FtpWebResponse)ftp.GetResponse()).GetResponseStream();
26}
27
28staticStreamGetHttpStream(thisUriuri)
29{
30return((HttpWebResponse)((HttpWebRequest)WebRequest.Create(uri)).GetResponse()).GetResponseStream();
31}
32
33staticStreamGetFileStream(thisUriuri)
34{
35return((FileWebResponse)((FileWebRequest)WebRequest.Create(uri)).GetResponse()).GetResponseStream();
36}
37}
38}
复制代码
上述程序中:
第9到17行的GetInputStream扩展方法返回来读取的数据的输入流。
第11行调用Uri类的静态方法IsWellFormedUriString判断是否从网络上读取数据。如不是,则直接调用File类的静态方法OpenRead得到输入流。
第12行构造一个Uri类的实例。
第13行处理输入使用http或者https协议的情况。
第14行处理输入使用ftp协议的情况。
第15行处理输入使用file协议的情况。
第16行处理其他协议,就是直接抛出一个NotSupportedException异常,表示我们只支持上述四种协议。
第19到26行的GetFtpStream扩展方法用于获得FTP服务器上发送的响应数据的输入流,可以是匿名的,也可以是非匿名的。
第28到31行的GetHttpStream扩展方法用于获得使用http或者https协议的网络流。
第33到36行的GetFileStream扩展方法用于获得使用file协议的本地磁盘文件系统的数据流。
下面就是测试用的CopyTester.cs:
复制代码
1usingSystem.IO;
2
3namespaceSkyiv.Test
4{
5staticclassCopyTester
6{
7staticvoidMain(string[]args)
8{
9args[0].GetInputStream().CopyTo(File.Create(args[1]));
10}
11}
12}
复制代码
这个测试程序的功能就是拷贝数据,需要两个命令行参数:
第一个命令行参数指定数据来源,可以是本地磁盘文件,也可以是网络数据,支持https、http、ftp和file协议,当然,file协议实际上还是读取本地磁盘文件。
第二个命令行参数指定将要拷贝到的本地磁盘文件的名称。
上述测试程序实质内容就是第9行的语句:
使用第一个命令行参数args[0]调用String类的GetInputStream扩展方法得到输入流。
调用Stream类的CopyTo方法将输入流拷贝到输出流。
输出流是使用File类的静态方法Create得到的。
在Windows操作系统中编译和运行:
E:\work>cscCopyTester.csStringExtensions.cs
Microsoft(R)VisualC#2010编译器4.0.30319.1版
版权所有(C)MicrosoftCorporation。保留所有权利。
E:\work>CopyTesterhttps://github.com/mono/xsp/zipball/mastermono-xsp.zip
E:\work>CopyTesterhttp://mysql.ntu.edu.tw/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zipmysql-connector.zip
E:\work>CopyTesterftp://ftp.ntu.edu.tw/pub/MySQL/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zipmysql-connector.2.zip
E:\work>CopyTesterfile:///E:/work/mysql-connector.zipmysql-connector.3.zip
E:\work>CopyTestermysql-connector.zipmysql-connector.4.zip
E:\work>dir.zip
2012/03/1109:35468,024mono-xsp.zip
2012/03/1109:374,176,361mysql-connector.2.zip
2012/03/1109:384,176,361mysql-connector.3.zip
2012/03/1109:384,176,361mysql-connector.4.zip
2012/03/1109:364,176,361mysql-connector.zip
上面分别测试了以https、http、ftp、file协议读取网络数据,以及从本地磁盘上读取数据。注意,file协议实际上还是从本地磁盘读取数据。
在Linux操作系统中编译和运行:
ben@vbox:~/work>dmcsCopyTester.csStringExtensions.cs
ben@vbox:~/work>monoCopyTester.exehttp://mysql.ntu.edu.tw/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zipmysql-connector.zip
ben@vbox:~/work>monoCopyTester.exeftp://ftp.ntu.edu.tw/pub/MySQL/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zipmysql-connector.2.zip
ben@vbox:~/work>monoCopyTester.exefile:///home/ben/work/mysql-connector.zipmysql-connector.3.zip
ben@vbox:~/work>monoCopyTester.exemysql-connector.zipmysql-connector.4.zip
ben@vbox:~/work>ls-l.zip
-rw-r--r--1benusers4176361Mar1109:54mysql-connector.2.zip
-rw-r--r--1benusers4176361Mar1110:01mysql-connector.3.zip
-rw-r--r--1benusers4176361Mar1110:01mysql-connector.4.zip
-rw-r--r--1benusers4176361Mar1109:53mysql-connector.zip
在Windows操作系统可以正常读取网络上的https数据流,在Linux操作系统中会失败:
ben@vbox:~/work>monoCopyTester.exehttps://github.com/mono/xsp/zipball/mastermono-xsp.zip
UnhandledException:System.Net.WebException:Errorgettingresponsestream(Write:Theauthenticationordecryptionhasfailed.):SendFailure--->System.IO.IOException:Theauthenticationordecryptionhasfailed.--->Mono.Security.Protocol.Tls.TlsException:Invalidcertificatereceivedfromserver.Errorcode:0xffffffff800b010a
atMono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates(Mono.Security.X509.X509CertificateCollectioncertificates)[0x00000]in:0
atMono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1()[0x00000]in:0
atMono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process()[0x00000]in:0
at(wrapperremoting-invoke-with-check)Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process()
atMono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage(Mono.Security.Protocol.Tls.TlsStreamhandMsg)[0x00000]in:0
atMono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback(IAsyncResultasyncResult)[0x00000]in:0
---Endofinnerexceptionstacktrace---
atMono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback(IAsyncResultasyncResult)[0x00000]in:0
---Endofinnerexceptionstacktrace---
atSystem.Net.HttpWebRequest.EndGetResponse(IAsyncResultasyncResult)[0x00000]in:0
atSystem.Net.HttpWebRequest.GetResponse()[0x00000]in:0
atSkyiv.StringExtensions.GetHttpStream(System.Uriuri)[0x00000]in:0
atSkyiv.StringExtensions.GetInputStream(System.StringfileNameOrUri,System.Stringuser,System.Stringpassword)[0x00000]in:0
atSkyiv.Test.CopyTester.Main(System.String[]args)[0x00000]in:0
[ERROR]FATALUNHANDLEDEXCEPTION:System.Net.WebException:Errorgettingresponsestream(Write:Theauthenticationordecryptionhasfailed.):SendFailure--->System.IO.IOException:Theauthenticationordecryptionhasfailed.--->Mono.Security.Protocol.Tls.TlsException:Invalidcertificatereceivedfromserver.Errorcode:0xffffffff800b010a
atMono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates(Mono.Security.X509.X509CertificateCollectioncertificates)[0x00000]in:0
atMono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1()[0x00000]in:0
atMono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process()[0x00000]in:0
at(wrapperremoting-invoke-with-check)Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process()
atMono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage(Mono.Security.Protocol.Tls.TlsStreamhandMsg)[0x00000]in:0
atMono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback(IAsyncResultasyncResult)[0x00000]in:0
---Endofinnerexceptionstacktrace---
atMono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback(IAsyncResultasyncResult)[0x00000]in:0
---Endofinnerexceptionstacktrace---
atSystem.Net.HttpWebRequest.EndGetResponse(IAsyncResultasyncResult)[0x00000]in:0
atSystem.Net.HttpWebRequest.www.baiyuewang.netGetResponse()[0x00000]in:0
atSkyiv.StringExtensions.GetHttpStream(System.Uriuri)[0x00000]in:0
atSkyiv.StringExtensions.GetInputStream(System.StringfileNameOrUri,System.Stringuser,System.Stringpassword)[0x00000]in:0
atSkyiv.Test.CopyTester.Main(System.String[]args)[0x00000]in:0
不知道是不是我的openSUSE12.1操作系统或者是Mono2.10.6运行环境还需要进行一些配置,以便满足https的安全验证要求。但是我在Windows操作系统中也没有进行特别的配置。而且在Linux操作系统中使用wget命令也能够下载https协议的数据:
ben@vbox:~/work>wgethttps://github.com/mono/xsp/zipball/master
askinglibproxyabouturl''https://github.com/mono/xsp/zipball/master''
libproxysuggesttouse''direct://''
--2012-03-1113:48:32--https://github.com/mono/xsp/zipball/master
Resolvinggithub.com(github.com)...207.97.227.239
Connectingtogithub.com(github.com)|207.97.227.239|:443...connected.
HTTPrequestsent,awaitingresponse...302Found
Location:https://nodeload.github.com/mono/xsp/zipball/master[following]
askinglibproxyabouturl''https://nodeload.github.com/mono/xsp/zipball/master''
libproxysuggesttowww.wang027.comuse''direct://''
--2012-03-1113:48:34--https://nodeload.github.com/mono/xsp/zipball/master
Resolvingnodeload.github.com(nodeload.github.com)...207.97.227.252
Connectingtonodeload.github.com(nodeload.github.com)|207.97.227.252|:443...connected.
HTTPrequestsent,awaitingresponse...200OK
Length:468024(457K)[application/octet-stream]
Savingto:`master''
100%[======================================>]468,02446.5K/sin17s
2012-03-1113:48:54(27.0KB/s)-`master''saved[468024/468024]
ben@vbox:~/work>mvmastermono-xsp.zip
这样看来,Mono环境的HttpWebRequest类可能需要进行一些设置才能读取https协议的数据。
|
|