配色: 字号:
给 string 增加一个 GetInputStream 扩展方法
2016-11-05 | 阅:  转:  |  分享 
  
给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协议的数据。

献花(0)
+1
(本文系thedust79首藏)