有时候,我们须要读取一些数据,而无论这数据来源于磁盘上的数据文件,还是来源于网络上的数据。于是。就有了以下的 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 协议的数据。

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

给 string 添加一个 GetInputStream 扩展方法的更多相关文章

  1. C# 向IQueryable添加一个Include扩展方法

    using System; using System.Data.Objects; using System.Linq; namespace OutOfMemory.Codes { /// <su ...

  2. 添加一个js扩展方法

    String.prototype.repeatify=String.prototype.repeatify || function(times){ var str=''; for(var i=0;i& ...

  3. 给IConfiguration写一个GetAppSetting扩展方法

    给 IConfiguration 写一个 GetAppSetting 扩展方法 Intro 在 .net core 中,微软已经默认使用 appsettings.json 来代替 app.config ...

  4. Qt applendPlainText()/append() 多添加一个换行解决方法

    Qt applendPlainText()/append() 多添加一个换行解决方法 void ConsoleDialog::appendMessageToEditor(const QString & ...

  5. 一个利用扩展方法的实例:AttachDataExtensions

    扩展方法是C# 3.0(老赵对VB不熟)中最简单,也是最常用的语言特性之一.这是老赵自以为的一个简单却不失经典的实例: [AttributeUsage(AttributeTargets.All, Al ...

  6. 在 JavaScript 中,我们能为原始类型添加一个属性或方法吗?

    原始类型的方法 JavaScript 允许我们像使用对象一样使用原始类型(字符串,数字等).JavaScript 还提供了这样的调用方法.我们很快就会学习它们,但是首先我们将了解它的工作原理,毕竟原始 ...

  7. [javascript]String添加trim和reverse方法

    function trim() { var start, end; start = 0; end = this.length - 1; while(start <= end && ...

  8. Flutter——Dart Extension扩展方法的使用

    dart的extension方法可以给已经存在的类添加新的函数,通过extension我们可以封装一些常用方法,提高开发效率. 例一:扩展String 给string添加一个log打印方法 exten ...

  9. 为system对象添加扩展方法

    ////扩展方法类:必须为非嵌套,非泛型的静态类 public static class DatetimeEx { //通过this声明扩展的类,这里给DateTime类扩展一个Show方法,只有一个 ...

随机推荐

  1. BZOJ 1005 [HNOI2008]明明的烦恼 purfer序列,排列组合

    1005: [HNOI2008]明明的烦恼 Description 自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少 ...

  2. Android+Jquery Mobile学习系列-目录

    最近在研究学习基于Android的移动应用开发,准备给家里人做一个应用程序用用.向公司手机移动团队咨询了下,觉得使用Android的WebView上手最快,因为WebView等于是一个内置浏览器,可以 ...

  3. Spark中常用的算法

    Spark中常用的算法: 3.2.1 分类算法 分类算法属于监督式学习,使用类标签已知的样本建立一个分类函数或分类模型,应用分类模型,能把数据库中的类标签未知的数据进行归类.分类在数据挖掘中是一项重要 ...

  4. [Javascript] 40个轻量级JavaScript脚本库

    诸如jQuery, MooTools, Prototype, Dojo和YUI等JavaScript脚本库,大家都已经很熟悉.但这些脚本库有利也有弊--比如说JavaScript文件过大的问题.有时你 ...

  5. 如何提升SQL语句的查询性能

    在对数据库进行操作时,如果SQL语句书写不当,对程序的效率会造成很大影响. 提高SQL效率可以从一下几个方面入手: 1,数据库设计与规划 Primary Key字段的长度尽量小,能用small int ...

  6. RT-Thread 设备驱动SPI浅析及使用

    OS版本:RT-Thread 4.0.0 测试BSP:STM32F407 SPI简介 SPI总线框架其实和I2C差不多,可以说都是总线设备+从设备,但SPI设备的通信时序配置并不固定,也就是说控制特定 ...

  7. 在量化金融中15个最流行的Python数据分析库

    Python是当今应用最广泛的编程语言之一,以其效率和代码可读性著称.作为一个科学数据的编程语言,Python介于R和java之间,前者主要集中在数据分析和可视化,而后者主要应用于大型应用.这种灵活性 ...

  8. LeetCode Weekly Contest 22

    1. 532. K-diff Pairs in an Array 分析:由于要唯一,所以要去重,考虑k=0,时候,相同的数字需要个数大于1,所以,先用map统计个数,对于k=0,特判,对于其他的,遍历 ...

  9. NPOI导出功能

    利用NPOI组件将数据中想要的数据导出到excel表格中. demo如下 using System; using System.Collections.Generic; using System.Li ...

  10. LruCache缓存机制

    LruCache: Android提供的使用了(Least Recently Used)近期最少使用算法的缓存类 内部基于LinkedHashMap实现 实现这个主要需要重写 构造时需要确定Cache ...