• 给 string 添加一个 GetInputStream 扩展方法


    有时候,我们须要读取一些数据,而无论这数据来源于磁盘上的数据文件,还是来源于网络上的数据。于是。就有了以下的 StringExtensions.cs:

    复制代码
     1 using System;
     2 using System.IO;
     3 using System.Net;
     4 
     5 namespace Skyiv
     6 {
     7   public static class StringExtensions
     8   {
     9     public static Stream GetInputStream(this string fileNameOrUri, string user = null, string password = null)
    10     {
    11       if (!Uri.IsWellFormedUriString(fileNameOrUri, UriKind.Absolute)) return File.OpenRead(fileNameOrUri);
    12       var uri = new Uri(fileNameOrUri);
    13       if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) return uri.GetHttpStream();
    14       if (uri.Scheme == Uri.UriSchemeFtp) return uri.GetFtpStream(user, password);
    15       if (uri.Scheme == Uri.UriSchemeFile) return uri.GetFileStream();
    16       throw new NotSupportedException("Notsupported uri scheme: " + uri.Scheme);
    17     }
    18 
    19     static Stream GetFtpStream(this Uri uri, string user = null, string password = null)
    20     {
    21       var ftp = (FtpWebRequest)WebRequest.Create(uri);
    22       if (user != null && user != "anonymous" && user != "ftp")
    23         ftp.Credentials = new NetworkCredential(user, password);
    24       ftp.Method = WebRequestMethods.Ftp.DownloadFile;
    25       return ((FtpWebResponse)ftp.GetResponse()).GetResponseStream();
    26     }
    27 
    28     static Stream GetHttpStream(this Uri uri)
    29     {
    30       return ((HttpWebResponse)((HttpWebRequest)WebRequest.Create(uri)).GetResponse()).GetResponseStream();
    31     }
    32 
    33     static Stream GetFileStream(this Uri uri)
    34     {
    35       return ((FileWebResponse)((FileWebRequest)WebRequest.Create(uri)).GetResponse()).GetResponseStream();
    36     }
    37   }
    38 }
    复制代码

    上述程序中:

    1. 第 9 到 17 行的 GetInputStream 扩展方法返回来读取的数据的输入流。
    2. 第 11 行调用 Uri 类的静态方法 IsWellFormedUriString 推断是否从网络上读取数据。如不是。则直接调用 File 类的静态方法 OpenRead 得到输入流。
    3. 第 12 行构造一个 Uri 类的实例。
    4. 第 13 行处理输入使用 http 或者 https 协议的情况。
    5. 第 14 行处理输入使用 ftp 协议的情况。
    6. 第 15 行处理输入使用 file 协议的情况。
    7. 第 16 行处理其它协议。就是直接抛出一个 NotSupportedException 异常。表示我们仅仅支持上述四种协议。

    8. 第 19 到 26 行的 GetFtpStream 扩展方法用于获得 FTP server上发送的响应数据的输入流。能够是匿名的。也能够是非匿名的。
    9. 第 28 到 31 行的 GetHttpStream 扩展方法用于获得使用 http 或者 https 协议的网络流。

    10. 第 33 到 36 行的 GetFileStream 扩展方法用于获得使用 file 协议的本地磁盘文件系统的数据流。

    以下就是測试用的 CopyTester.cs:

    复制代码
     1 using System.IO;
     2 
     3 namespace Skyiv.Test
     4 {
     5   static class CopyTester
     6   {
     7     static void Main(string[] args)
     8     {
     9       args[0].GetInputStream().CopyTo(File.Create(args[1]));
    10     }
    11   }
    12 }
    复制代码

    这个測试程序的功能就是拷贝数据,须要两个命令行參数:

    1. 第一个命令行參数指定数据来源,能够是本地磁盘文件。也能够是网络数据,支持 https、http、ftp 和 file 协议,当然,file 协议实际上还是读取本地磁盘文件。
    2. 第二个命令行參数指定将要复制到的本地磁盘文件的名称。

    上述測试程序实质内容就是第 9 行的语句:

    1. 使用第一个命令行參数 args[0] 调用 String 类的 GetInputStream 扩展方法得到输入流。
    2. 调用 Stream 类的 CopyTo 方法将输入流复制到输出流。
    3. 输出流是使用 File 类的静态方法 Create 得到的。

    在 Windows 操作系统中编译和执行:

    E:work> csc CopyTester.cs StringExtensions.cs
    Microsoft(R) Visual C# 2010 编译器 4.0.30319.1 版
    版权全部(C) Microsoft Corporation。

    保留全部权利。 E:work> CopyTester https://github.com/mono/xsp/zipball/master mono-xsp.zip E:work> CopyTester http://mysql.ntu.edu.tw/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zip mysql-connector.zip E:work> CopyTester ftp://ftp.ntu.edu.tw/pub/MySQL/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zip mysql-connector.2.zip E:work> CopyTester file:///E:/work/mysql-connector.zip mysql-connector.3.zip E:work> CopyTester mysql-connector.zip mysql-connector.4.zip E:work> dir *.zip 2012/03/11 09:35 468,024 mono-xsp.zip 2012/03/11 09:37 4,176,361 mysql-connector.2.zip 2012/03/11 09:38 4,176,361 mysql-connector.3.zip 2012/03/11 09:38 4,176,361 mysql-connector.4.zip 2012/03/11 09:36 4,176,361 mysql-connector.zip

    上面分别測试了以 https、http、ftp、file 协议读取网络数据,以及从本地磁盘上读取数据。注意。file 协议实际上还是从本地磁盘读取数据。

    在 Linux 操作系统中编译和执行:

    ben@vbox:~/work> dmcs CopyTester.cs StringExtensions.cs
    ben@vbox:~/work> mono CopyTester.exe http://mysql.ntu.edu.tw/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zip mysql-connector.zip
    ben@vbox:~/work> mono CopyTester.exe ftp://ftp.ntu.edu.tw/pub/MySQL/Downloads/Connector-Net/mysql-connector-net-6.5.4-noinstall.zip mysql-connector.2.zip
    ben@vbox:~/work> mono CopyTester.exe file:///home/ben/work/mysql-connector.zip mysql-connector.3.zip
    ben@vbox:~/work> mono CopyTester.exe mysql-connector.zip mysql-connector.4.zip
    ben@vbox:~/work> ls -l *.zip
    -rw-r--r-- 1 ben users 4176361 Mar 11 09:54 mysql-connector.2.zip
    -rw-r--r-- 1 ben users 4176361 Mar 11 10:01 mysql-connector.3.zip
    -rw-r--r-- 1 ben users 4176361 Mar 11 10:01 mysql-connector.4.zip
    -rw-r--r-- 1 ben users 4176361 Mar 11 09:53 mysql-connector.zip
    

    在 Windows 操作系统能够正常读取网络上的 https 数据流,在 Linux 操作系统中会失败:

    ben@vbox:~/work> mono CopyTester.exe https://github.com/mono/xsp/zipball/master mono-xsp.zip
    
    Unhandled Exception: System.Net.WebException: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server. Error code: 0xffffffff800b010a
      at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x00000] in :0
      at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00000] in :0
      at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00000] in :0
      at (wrapper remoting-invoke-with-check) Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process ()
      at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00000] in :0
      at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in :0
      --- End of inner exception stack trace ---
      at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in :0
      --- End of inner exception stack trace ---
      at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00000] in :0
      at System.Net.HttpWebRequest.GetResponse () [0x00000] in :0
      at Skyiv.StringExtensions.GetHttpStream (System.Uri uri) [0x00000] in :0
      at Skyiv.StringExtensions.GetInputStream (System.String fileNameOrUri, System.String user, System.String password) [0x00000] in :0
      at Skyiv.Test.CopyTester.Main (System.String[] args) [0x00000] in :0
    [ERROR] FATAL UNHANDLED EXCEPTION: System.Net.WebException: Error getting response stream (Write: The authentication or decryption has failed.): SendFailure ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server. Error code: 0xffffffff800b010a
      at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.validateCertificates (Mono.Security.X509.X509CertificateCollection certificates) [0x00000] in :0
      at Mono.Security.Protocol.Tls.Handshake.Client.TlsServerCertificate.ProcessAsTls1 () [0x00000] in :0
      at Mono.Security.Protocol.Tls.Handshake.HandshakeMessage.Process () [0x00000] in :0
      at (wrapper remoting-invoke-with-check) Mono.Security.Protocol.Tls.Handshake.HandshakeMessage:Process ()
      at Mono.Security.Protocol.Tls.ClientRecordProtocol.ProcessHandshakeMessage (Mono.Security.Protocol.Tls.TlsStream handMsg) [0x00000] in :0
      at Mono.Security.Protocol.Tls.RecordProtocol.InternalReceiveRecordCallback (IAsyncResult asyncResult) [0x00000] in :0
      --- End of inner exception stack trace ---
      at Mono.Security.Protocol.Tls.SslStreamBase.AsyncHandshakeCallback (IAsyncResult asyncResult) [0x00000] in :0
      --- End of inner exception stack trace ---
      at System.Net.HttpWebRequest.EndGetResponse (IAsyncResult asyncResult) [0x00000] in :0
      at System.Net.HttpWebRequest.GetResponse () [0x00000] in :0
      at Skyiv.StringExtensions.GetHttpStream (System.Uri uri) [0x00000] in :0
      at Skyiv.StringExtensions.GetInputStream (System.String fileNameOrUri, System.String user, System.String password) [0x00000] in :0
      at Skyiv.Test.CopyTester.Main (System.String[] args) [0x00000] in :0
    

    不知道是不是我的 openSUSE 12.1 操作系统或者是 Mono 2.10.6 执行环境还须要进行一些配置,以便满足 https 的安全验证要求。可是我在 Windows 操作系统中也没有进行特别的配置。并且在 Linux 操作系统中使用 wget 命令也可下面载 https 协议的数据:

    ben@vbox:~/work> wget https://github.com/mono/xsp/zipball/master
    asking libproxy about url 'https://github.com/mono/xsp/zipball/master'
    libproxy suggest to use 'direct://'
    --2012-03-11 13:48:32--  https://github.com/mono/xsp/zipball/master
    Resolving github.com (github.com)... 207.97.227.239
    Connecting to github.com (github.com)|207.97.227.239|:443... connected.
    HTTP request sent, awaiting response... 302 Found
    Location: https://nodeload.github.com/mono/xsp/zipball/master [following]
    asking libproxy about url 'https://nodeload.github.com/mono/xsp/zipball/master'
    libproxy suggest to use 'direct://'
    --2012-03-11 13:48:34--  https://nodeload.github.com/mono/xsp/zipball/master
    Resolving nodeload.github.com (nodeload.github.com)... 207.97.227.252
    Connecting to nodeload.github.com (nodeload.github.com)|207.97.227.252|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 468024 (457K) [application/octet-stream]
    Saving to: `master'
    
    100%[======================================>] 468,024  46.5K/s in 17s
    
    2012-03-11 13:48:54 (27.0 KB/s) - `master' saved [468024/468024]
    
    ben@vbox:~/work> mv master mono-xsp.zip
    

    这样看来。Mono 环境的 HttpWebRequest 类可能须要进行一些设置才干读取 https 协议的数据。

    假设有哪位园友知道的话,请在本文的评论里告诉我,谢谢。

  • 相关阅读:
    01-文件系统
    适配器模式,新老系统兼容
    01-Entity FrameWork如何控制数据的变化
    .Net实战之反射操作篇
    .Net实战之反射相关类之间的人体经络关系
    .Net实战之反射外卖计费
    [转]UINavigationController 返回的方法汇总
    [转]AFNetWorking使用笔记
    vue----子组件引用vux popup mask遮罩在最上层解决办法 z-index问题
    vue系列---vue项目(已安装vuex)中引入jquery
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/6950851.html
Copyright © 2020-2023  润新知