开源
程序设计
常用组件
加载图片,播放音乐、视频,摄像头拍照
文件读写(txt、xml、自定义文件格式(后缀名))
串口通信
稳定的串口读写:http://blog.csdn.net/kolvin2008/article/details/52833480
窗口通信类SerialPort:https://www.cnblogs.com/BookCode/p/5583853.html
用C#一步步写串口通信:http://blog.csdn.net/kasama1953/article/details/51434295
在win10环境下开发uwp程序,在调用bluetooth的API的时候出现问题
原帖地址:https://bbs.csdn.net/topics/392034336?locationNum=13&fps=1
蓝牙开发
用C#在windows上操控电脑自带蓝牙(入道指南)
原文地址:http://blog.csdn.net/yssjz960427031/article/details/50990372
前言
如题,如果你也想用C#在windows上操控电脑自带蓝牙,但是,不知从何下手,那就该看看这篇文章——这篇文章将带领你入道。也正是这样,这篇文章的主要内容是介绍操控蓝牙所需的支持库,以及从哪里下载最新版的支持库,并教你如何自学与蓝牙开发相关的更多知识等。本文涵盖了经典蓝牙(蓝牙2.0版本)和低功耗蓝牙(即BLE,蓝牙4.0版本)。
正文
有过一定编程经验的人都知道,要想操控某个平台上的一个硬件,第一件事就是搞清楚这个系统平台提供了哪些与该硬件相关的API给开发者用,或者,操控该硬件的第三方支持库有哪些。找到这些是第一步,也是最关键的一步。就像治病,首先要找到能治这个病的药,然后找到药的说明书,照着说明书“按时按量吃药治病”——做了个比较形象的比喻。之于开发人员,在找到支持库后,就该去找支持库作者提供的使用指南,然后按照使用指南学习使用这个支持库。那么,针对“不知道如何操控Windows上的蓝牙”这个病该用哪味药呢?——药就是这篇文章啦。现在就来按照说明书吃药啦。
下面分别介绍经典蓝牙和BLE相关的支持库。
经典蓝牙
稍微用诸如“C# 蓝牙”这样的关键词百度、Google下,就会发现InTheHand.Net.Personal.dll这个支持库,对!操控经典蓝牙就用这个。
简要介绍
InTheHand.Net.Personal.dll这个支持库是In The Hand公司下32FEET.NET这个项目的成果。该公司由Peter Foot创办,注册在英国。下文贴一张摘自官网的照片——看!就是这么帅,这才是男神级别的人物!
可通过如下链接了解更多的信息:
当给出了如上三个链接后,尤其是第三个,这部分的重点内容基本都讲完了。因为在“32FEET.NET项目的源码托管地址”这个页面中,就可以下载到最新版本的InTheHand.Net.Personal.dll这个支持库,也有这个库的使用指南,如下图所示:
下载支持库
说了这么多,这有个重点:生活在天朝,由于墙的存在,我们错过了很多人间的精彩。所以,你懂了……我为大家下载了最新的(2016.3.20下载) .Net 3.5和 .Net 3.7版本的InTheHand.Net.Personal.dll,你可从如下地址下载,里面附有简要的使用说明,使用零门槛:
使用示例
具体使用可参照官方的指导文档,也可以看看相关的博客,下面仅以我写过的控制笔记本电脑蓝牙来开门的代码演示下,要特别注意我在下边代码的注释中提到的3个注意——我是从这些坑中爬出来的有经验的人。
using System;
using System.IO;
using System.Net.Sockets; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; // [注意1]:要添加如下三个命名空间 using InTheHand.Net; using InTheHand.Net.Bluetooth; using InTheHand.Net.Sockets; namespace TestBluetooth { class Program { static void Main(string[] args) { BluetoothRadio bluetoothRadio = BluetoothRadio.PrimaryRadio; if (bluetoothRadio == null) { Console.WriteLine("没有找到本机蓝牙设备!"); } else { Program p = new Program(); p.localAdapterInfo(bluetoothRadio); p.openDoor(); } } /** * 连接目标蓝牙设备发送开门指令 * **/ private void openDoor() { BluetoothClient cli = new BluetoothClient(); BluetoothAddress addr = null; BluetoothEndPoint ep = null; try { // [注意2]:要注意MAC地址中字节的对应关系,直接来看顺序是相反的,例如 // 如下对应的MAC地址为——12:34:56:78:9a:bc addr = new BluetoothAddress(new byte[] { 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12 }); ep = new BluetoothEndPoint(addr, BluetoothService.SerialPort); cli.Connect(ep); // 连接蓝牙 if (cli.Connected) { Stream peerStream = cli.GetStream(); peerStream.WriteByte(0xBB); // 发送开门指令 } } catch (SocketException e) { Console.WriteLine(e.Message); } finally { if (cli != null) { // [注意3]:要延迟一定时间(例如1000毫秒) //避免因连接后又迅速断开而导致蓝牙进入异常(傻逼)状态 Thread.Sleep(1000); cli.Close(); } } } /** * * 显示本地蓝牙的信息 * * **/ private void localAdapterInfo(BluetoothRadio bluetoothRadio) { Console.WriteLine("ClassOfDevice: " + bluetoothRadio.ClassOfDevice); Console.WriteLine("HardwareStatus: " + bluetoothRadio.HardwareStatus); Console.WriteLine("HciRevision: " + bluetoothRadio.HciRevision); Console.WriteLine("HciVersion: " + bluetoothRadio.HciVersion); Console.WriteLine("LmpSubversion: " + bluetoothRadio.LmpSubversion); Console.WriteLine("LmpVersion: " + bluetoothRadio.LmpVersion); Console.WriteLine("LocalAddress: " + bluetoothRadio.LocalAddress); Console.WriteLine("Manufacturer: " + bluetoothRadio.Manufacturer); Console.WriteLine("Mode: " + bluetoothRadio.Mode); Console.WriteLine("Name: " + bluetoothRadio.Name); Console.WriteLine("Remote:" + bluetoothRadio.Remote); Console.WriteLine("SoftwareManufacturer: " + bluetoothRadio.SoftwareManufacturer); Console.WriteLine("StackFactory: " + bluetoothRadio.StackFactory); } } }
BLE
(PS:以下所述,都是假设你的笔记本上的蓝牙是支持BLE特性的)
毕竟智能硬件兴起,还玩经典蓝牙显得有点Low。那么,问题来了,在电脑上可不可以使用BLE呢?答案是——可以!
但是,有条件限制:只能在Windows 8、Windows 8.1、Windows 10上玩。这个消息也不算太坏哈。
Q:为什么Windows 7上不能玩呢?
A:因为Windows 7及其以下的Windows操作系统中的蓝牙协议栈不支持BLE特性。这就比如,你分明在你的笔记本上接了一台带扫描功能的打印机,但是你只能打印却用不了扫描功能,因为你装的驱动不支持扫描功能。电脑面对的是一台既可以打印又可以扫描的的机器,但是就是不知道如何去控制它来进行扫描。同理,如果硬件支持了BLE(即蓝牙4.0)特性,但是蓝牙协议栈里缺少一些支持这些特性的内容,就没得玩了。
Q:那么,我可以装个强大点的“驱动”么?
A:不可以,这个协议栈不同于一般的驱动,Windows的源码是微软老大哥一手掌控的,没有源码,我们装不进去!
Q:那么,真的就没得完了么?
A:换系统呗,换成8及其以上的,一切妥妥的!
想知道Windows系统对蓝牙的具体支持情况,请点击:General Bluetooth Support in Windows
BLE支持库
- 首先,InTheHand.Net.Personal.dll这个库不支持BLE,因为,Windows系统有与BLE相关的API了,作者表示暂时没有考虑在Windows的API上再包一层,详情可见论坛的帖子:Bluetooth Low Energy Support,男神是这么回复的:
不过回复时间是2013.5.15,有点久远了,最新的情况,有兴趣的可以继续一探究竟。 - 使用Windows的提供API:详情见Windows.Devices.Bluetooth.GenericAttributeProfile namespace
与Windows开发相关的“说明书”,可以从Windows开发者中心获得。沿着这条路,你也可以直接走到与蓝牙开发相关的部分:
Windows 开发者中心—>文档—>应用—>API参考—>Windows运行时API
—> Windows.Devices.Bluetooth.GenericAttributeProfile namespace
温馨提示
学习GATT协议是进行BLE开发的基础,BLE的通讯方式和经典蓝牙的通讯方式有很大的区别,要注意思维转换,如果还是从Socket通讯的方式来学习BLE的话,可能会遇到麻烦。
结语
我用C#操作笔记本电脑的蓝牙来开门也是出于兴趣,上文正是记录了我从当初的无处下爪到最后有成果这个过程中的经验所得,记录并将其分享出来,希望能够给大家一些帮助、鼓励甚至启发,如果能通过我的文字让别人不要走我走过的弯路,哪怕只有一个,也甚是欣慰了。
C#开发蓝牙服务端,自动配对以及收发消息
地址:http://blog.csdn.net/oqzuser12345678923/article/details/51252545
目前.Net平台最好用的蓝牙库是InTheHand.net,是由32feet.net提供的shared-source项目,提供短距离领域(personal area networking technologie)的通信功能,支持bluetooth,Infrared(IrDA)红外等.
//启动一个监听线程
Thread listenThread = new Thread(ReceiveData);
listenThread.IsBackground = true;
listenThread.Start();
//监听方法
public void ReceiveData() { while (1 == 1) { try { Guid mGUID = Guid.Parse("db764ac8-4b08-7f25-aafe-59d03c27bae3"); bluetoothListener = new BluetoothListener(mGUID); bluetoothListener.Start(); bluetoothClient = bluetoothListener.AcceptBluetoothClient(); isConnected = true; while (isConnected) { if (bluetoothClient != null && bluetoothClient.Connected) { peerStream = bluetoothClient.GetStream(); } else { break; } byte[] buffer = new byte[100]; peerStream.Read(buffer, 0, 100); receive = Encoding.UTF8.GetString(buffer).ToString(); if (receive == temp) { isConnected = false; } Console.WriteLine(receive + "receiveMsg"); } bluetoothListener.Stop(); bluetoothClient = null; } catch (Exception ex) { Console.Write(ex.Message); } } }
两个while循环是因为我的安卓app没法修改,没有做断开处理,所以强行在服务端断开了。
如果你蓝牙连接着的,并且和电脑配对上了,那用这个方法是可以接受消息的。
那么现在问题来了。
我的windows主机是没有输出设备的,木有显示器,而蓝牙配对有3中方法,其中justwork表示不验证,直接配对,但是客户端代码动不了,inTheHand.net也没有找到怎么设置配对模式。
最后找到蓝牙配对PING码确认的事件,直接把事件注册后,响应通过就行了。
EventHandler<BluetoothWin32AuthenticationEventArgs> handler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(this.handleRequests);
BluetoothWin32Authentication authenticator = new BluetoothWin32Authentication(handler);
public void handleRequests(Object thing, BluetoothWin32AuthenticationEventArgs args) { args.Confirm = true; }
异步回调
下面是一个异步回调的例子,主要是发出Post请求,等收到Post请求结果后调用回调方法Done显示收到的结果。
命名空间
using System.Runtime.Remoting.Messaging;
public delegate string PostHandler(string url, string parame); private void SendPost(string url, string fileName) { try { string paramData = string.Empty; if (!string.IsNullOrEmpty(fileName)) { using (StreamReader sr = new StreamReader(fileName, Encoding.Default)) { paramData = sr.ReadToEnd().Trim(); } } PostHandler postHandler = new PostHandler(Post); IAsyncResult result = postHandler.BeginInvoke(url, paramData, new AsyncCallback(Done), postHandler); } catch (Exception ex) { MessageBox.Show("出错!异常为:" + ex.Message); } } public void Done(IAsyncResult result) { PostHandler handler = (PostHandler)((AsyncResult)result).AsyncDelegate; string resultStr = handler.EndInvoke(result); if (!string.IsNullOrEmpty(resultStr)) { DisplayResult(resultStr); } else { DisplayResult("未收到结果,请重新发送!"); } MessageBox.Show("收到结果!"); } private void DisplayResult(string result) { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(delegate() { DisplayResult(result); })); } else { textBox_Result.Text = result; } } //public CookieContainer CookieContainer { get; set; } private string Post(string postUrl, string paramData) { string result = string.Empty; Stream stream = null; StreamReader sr = null; HttpWebResponse response = null; try { byte[] byteArray = Encoding.UTF8.GetBytes(paramData); HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(new Uri(postUrl)); webReq.Method = "POST"; webReq.ContentType = "application/json; charset=utf-8"; //webReq.ContentType = "application/x-www-form-urlencoded"; webReq.Accept = "text/json"; //"image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"; webReq.UserAgent = "valwell.com/1.0"; webReq.ContentLength = byteArray.Length; webReq.ServicePoint.Expect100Continue = false; //webReq.CookieContainer = CookieContainer; stream = webReq.GetRequestStream(); stream.Write(byteArray, 0, byteArray.Length); response = (HttpWebResponse)webReq.GetResponse(); if (response.StatusCode == HttpStatusCode.OK) { //response.Cookies = CookieContainer.GetCookies(webReq.RequestUri); sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8); result = sr.ReadToEnd(); } else { Debug.WriteLine(response.StatusCode); } } catch (Exception ex) { string exMessage = ex.Message; } finally { if (sr != null) { sr.Close(); } if (response != null) { response.Close(); } if (stream != null) { stream.Close(); } } return result; } /// <summary> /// 设置是否允许不安全的连接 /// </summary> /// <param name="useUnsafe"></param> /// <returns></returns> public static bool SetAllowUnsafeHeaderParsing20(bool useUnsafe) { //Get the assembly that contains the internal class System.Reflection.Assembly aNetAssembly = System.Reflection.Assembly.GetAssembly(typeof(System.Net.Configuration.SettingsSection)); if (aNetAssembly != null) { //Use the assembly in order to get the internal type for the internal class Type aSettingsType = aNetAssembly.GetType("System.Net.Configuration.SettingsSectionInternal"); if (aSettingsType != null) { //Use the internal static property to get an instance of the internal settings class. //If the static instance isn't created allready the property will create it for us. object anInstance = aSettingsType.InvokeMember("Section", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.NonPublic, null, null, new object[] { }); if (anInstance != null) { //Locate the private bool field that tells the framework is unsafe header parsing should be allowed or not System.Reflection.FieldInfo aUseUnsafeHeaderParsing = aSettingsType.GetField("useUnsafeHeaderParsing", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); if (aUseUnsafeHeaderParsing != null) { aUseUnsafeHeaderParsing.SetValue(anInstance, useUnsafe); return true; } } } } return false; }
C#使用Log4Net记录日志
参考文档网址:
1、http://www.cnblogs.com/wangsaiming/archive/2013/01/11/2856253.html
2、http://www.cnblogs.com/jys509/p/4569874.html
3、http://zhoufoxcn.blog.51cto.com/792419/429988/
4、http://blog.csdn.net/suixufeng/article/details/50259617
有时间自己再写一篇专门的文档
文件读写
一、获取路径
1.获取和设置当前目录的完全限定路径。 string str = System.Environment.CurrentDirectory;
Result: C:\xxx\xxx
2.获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。 string str = System.Windows.Forms.Application.StartupPath; Result: C:\xxx\xxx
3.获取新的 Process 组件并将其与当前活动的进程关联的主模块的完整路径,包含文件名。 string str = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; Result: C:\xxx\xxx\xxx.exe
4.获取当前 Thread 的当前应用程序域的基目录,它由程序集冲突解决程序用来探测程序集。 string str = System.AppDomain.CurrentDomain.BaseDirectory; Result: C:\xxx\xxx\
5.获取应用程序的当前工作目录。 string str = System.IO.Directory.GetCurrentDirectory();
Result: C:\xxx\xxx
6.获取和设置包含该应用程序的目录的名称。 string str = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase; Result: C:\xxx\xxx\
7.获取当前进程的完整路径,包含文件名。 string str = this.GetType().Assembly.Location;
Result: C:\xxx\xxx\xxx.exe
8.获取启动了应用程序的可执行文件的路径,包括可执行文件的名称。 string str = System.Windows.Forms.Application.ExecutablePath; Result: C:\xxx\xxx\xxx.exe
二、目录与文件(Directory类和File类)
下面是一个例子,原文地址http://www.cnblogs.com/szytwo/archive/2012/03/22/2411703.html
protected void Button1_Click(object sender, EventArgs e)
{
if (Directory.Exists(Server.MapPath("~/upimg/hufu")) == false)//如果不存在就创建file文件夹
{
Directory.CreateDirectory(Server.MapPath("~/upimg/hufu"));
}
//Directory.Delete(Server.MapPath("~/upimg/hufu"), true);//删除文件夹以及文件夹中的子目录,文件
//判断文件的存在
if (File.Exists(Server.MapPath("~/upimg/Data.html")))
{
Response.Write("Yes");
//存在文件
}
else
{
Response.Write("No");
//不存在文件
File.Create(MapPath("~/upimg/Data.html"));//创建该文件
}
string name = GetFiles.FileName;//获取已上传文件的名字
string size = GetFiles.PostedFile.ContentLength.ToString();//获取已上传文件的大小
string type = GetFiles.PostedFile.ContentType;//获取已上传文件的MIME
string postfix = name.Substring(name.LastIndexOf(".") + 1);//获取已上传文件的后缀
string ipath = Server.MapPath("upimg") +"\\"+ name;//获取文件的实际路径
string fpath = Server.MapPath("upfile") + "\\" + name;
string dpath = "upimg\\" + name;//判断写入数据库的虚拟路径
ShowPic.Visible = true;//激活
ShowText.Visible = true;//激活
//判断文件格式
if (name == "") {
Response.Write("<script>alert('上传文件不能为空')</script>");
}
else{
if (postfix == "jpg" || postfix == "gif" || postfix == "bmp" || postfix == "png")
{
GetFiles.SaveAs(ipath);
ShowPic.ImageUrl = dpath;
ShowText.Text = "你上传的图片名称是:" + name + "<br>" + "文件大小:" + size + "KB" + "<br>" + "文件类型:" + type + "<br>" + "存放的实际路径为:" + ipath;
}
else
{
ShowPic.Visible = false;//隐藏图片
GetFiles.SaveAs(fpath);//由于不是图片文件,因此转存在upfile这个文件夹
ShowText.Text = "你上传的文件名称是:" + name + "<br>" + "文件大小:" + size + "KB" + "<br>" + "文件类型:" + type + "<br>" + "存放的实际路径为:" + fpath;
}
三、文件的读写
C#对文本文件的几张读写方法总结,原文地址http://www.cr173.com/html/18141_1.html
计算机在最初只支持ASCII编码,但是后来为了支持其他语言中的字符(比如汉字)以及一些特殊字符(比如€),就引入了Unicode字符集。基于Unicode字符集的编码方式有很多,比如UTF-7、UTF-8、Unicode以及UTF-32。在Windows操作系统中,一个文本文件的前几个字节是用来指定该文件的编码方式的。
如果你使用NotePad或WordPad来打开一个文本文件,你并不用担心该文件的编码方式,因为这些应用程序会先读取文件的前几个字节来确定该文件的编码方式,然后用正确的编码将文本中的每个字符显示出来。下面的图中,可以看到当用NotePad记事本保存一个文档时,可以选择的编码(Encoding)方式有哪些。
用.Net读取文本文件或写入文本文件,你都不须要担心编码方式。.Net已经将这些封装好了。在读取一个文本文件的时候,如果你已经知道文本使用的是什么编码方式,你可以指定使用哪种编码方式读取文本,否则如果不指定编码方式,.Net会读取文本的前几个字节来确定使用哪种编码方式读取文件内容的。在写入文本文件的时候,你也可以指定你想使用的编码方式。如果你没有指定编码,.Net会根据写入的文本是否含有特殊字符来决定编码方式。如果没有特殊字符,就采用ASCII编码,如果有特殊字符,就采用UTF-8编码。
(一) 读取文件
如果你要读取的文件内容不是很多,可以使用 File.ReadAllText(FilePath) 或指定编码方式 File.ReadAllText(FilePath, Encoding)的方法。
它们都一次将文本内容全部读完,并返回一个包含全部文本内容的字符串
string str = File.ReadAllText(@"c:\temp\ascii.txt");
// 也可以指定编码方式
string str2 = File.ReadAllText(@"c:\temp\ascii.txt", Encoding.ASCII);
也可以使用方法File.ReadAllLines。该方法返回一个字符串数组。每一行都是一个数组元素。
string[] strs = File.ReadAllLines(@"c:\temp\ascii.txt");
// 也可以指定编码方式
string[] strs2 = File.ReadAllLines(@"c:\temp\ascii.txt", Encoding.ASCII);
当文本的内容比较大时,我们就不要将文本内容一次读完,而应该采用流(Stream)的方式来读取内容。.Net为我们封装了StreamReader类。初始化StreamReader类有很多种方式。下面我罗列出几种
StreamReader sr1 = new StreamReader(@"c:\temp\utf-8.txt");
// 同样也可以指定编码方式
StreamReader sr2 = new StreamReader(@"c:\temp\utf-8.txt", Encoding.UTF8);
FileStream fs = new FileStream(@"C:\temp\utf-8.txt", FileMode.Open, FileAccess.Read, FileShare.None);
StreamReader sr3 = new StreamReader(fs);
StreamReader sr4 = new StreamReader(fs, Encoding.UTF8);
FileInfo myFile = new FileInfo(@"C:\temp\utf-8.txt");
// OpenText 创建一个UTF-8 编码的StreamReader对象
StreamReader sr5 = myFile.OpenText();
// OpenText 创建一个UTF-8 编码的StreamReader对象
StreamReader sr6 = File.OpenText(@"C:\temp\utf-8.txt");
初始化完成之后,你可以每次读一行,也可以每次读一个字符 ,还可以每次读几个字符,甚至也可以一次将所有内容读完。
// 读一行
string nextLine = sr.ReadLine();
// 读一个字符
int nextChar = sr.Read();
// 读100个字符
int nChars = 100;
char[] charArray = new char[nChars];
int nCharsRead = sr.Read(charArray, 0, nChars);
// 全部读完
string restOfStream = sr.ReadToEnd();
使用完StreamReader之后,不要忘记关闭它: sr.Closee();
假如我们需要一行一行的读,将整个文本文件读完,下面看一个完整的例子:
StreamReader sr = File.OpenText(@"C:\temp\ascii.txt");
string nextLine;
while ((nextLine = sr.ReadLine()) != null)
{
Console.WriteLine(nextLine);
}
sr.Close();
(二) 写入文件
写文件和读文件一样,如果你要写入的内容不是很多,可以使用File.WriteAllText方法来一次将内容全部写如文件。如果你要将一个字符串的内容写入文件,可以用File.WriteAllText(FilePath) 或指定编码方式 File.WriteAllText(FilePath, Encoding)方法。
string str1 = "Good Morning!"; File.WriteAllText(@"c:\temp\test\ascii.txt", str1); // 也可以指定编码方式 File.WriteAllText(@"c:\temp\test\ascii-2.txt", str1, Encoding.ASCII);
如果你有一个字符串数组,你要将每个字符串元素都写入文件中,可以用File.WriteAllLines方法:
string[] strs = { "Good Morning!", "Good Afternoon!" }; File.WriteAllLines(@"c:\temp\ascii.txt", strs); File.WriteAllLines(@"c:\temp\ascii-2.txt", strs, Encoding.ASCII);
使用File.WriteAllText或File.WriteAllLines方法时,如果指定的文件路径不存在,会创建一个新文件;如果文件已经存在,则会覆盖原文件。
当要写入的内容比较多时,同样也要使用流(Stream)的方式写入。.Net封装的类是StreamWriter。初始化StreamWriter类同样有很多方式:
// 如果文件不存在,创建文件; 如果存在,覆盖文件
StreamWriter sw1 = new StreamWriter(@"c:\temp\utf-8.txt");
// 也可以指定编码方式
// true 是 append text, false 为覆盖原文件
StreamWriter sw2 = new StreamWriter(@"c:\temp\utf-8.txt", true, Encoding.UTF8);
// FileMode.CreateNew: 如果文件不存在,创建文件;如果文件已经存在,抛出异常
FileStream fs = new FileStream(@"C:\temp\utf-8.txt", FileMode.CreateNew, FileAccess.Write, FileShare.Read);
// UTF-8 为默认编码
StreamWriter sw3 = new StreamWriter(fs);
StreamWriter sw4 = new StreamWriter(fs, Encoding.UTF8);
// 如果文件不存在,创建文件; 如果存在,覆盖文件
FileInfo myFile = new FileInfo(@"C:\temp\utf-8.txt");
StreamWriter sw5 = myFile.CreateText();
初始化完成后,可以用StreamWriter对象一次写入一行,一个字符,一个字符数组,甚至一个字符数组的一部分。
// 写一个字符
sw.Write('a');
// 写一个字符数组
char[] charArray = new char[100];
// initialize these characters
sw.Write(charArray);
// 写一个字符数组的一部分
sw.Write(charArray, 10, 15);
同样,StreamWriter对象使用完后,不要忘记关闭。sw.Close(); 最后来看一个完整的使用StreamWriter一次写入一行的例子:
FileInfo myFile = new FileInfo(@"C:\temp\utf-8.txt");
StreamWriter sw = myFile.CreateText();
string[] strs = { "早上好", "下午好" };
foreach (var s in strs)
{
sw.WriteLine(s);
}
sw.Close();
写入文本文件例子
class WriteTextFile
{
static void Main()
{
//如果文件不存在,则创建;存在则覆盖
//该方法写入字符数组换行显示
string[] lines = { "first line", "second line", "third line","第四行" };
System.IO.File.WriteAllLines(@"C:\testDir\test.txt", lines, Encoding.UTF8);
//如果文件不存在,则创建;存在则覆盖
string strTest = "该例子测试一个字符串写入文本文件。";
System.IO.File.WriteAllText(@"C:\testDir\test1.txt", strTest, Encoding.UTF8);
//在将文本写入文件前,处理文本行
//StreamWriter一个参数默认覆盖
//StreamWriter第二个参数为false覆盖现有文件,为true则把文本追加到文件末尾
using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\testDir\test2.txt",true))
{
foreach (string line in lines)
{
if (!line.Contains("second"))
{
file.Write(line);//直接追加文件末尾,不换行
file.WriteLine(line);// 直接追加文件末尾,换行
}
}
}
}
}
读取文本文件例子
class ReadTextFile
{
static void Main()
{
//直接读取出字符串
string text = System.IO.File.ReadAllText(@"C:\testDir\test1.txt");
Console.WriteLine(text);
//按行读取为字符串数组
string[] lines = System.IO.File.ReadAllLines(@"C:\testDir\test.txt");
foreach (string line in lines)
{
Console.WriteLine(line);
}
//从头到尾以流的方式读出文本文件
//该方法会一行一行读出文本
using (System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\testDir\test.txt"))
{
string str;
while ((str = sr.ReadLine()) != null)
{
Console.WriteLine(str);
}
}
Console.Read();
}
}
四、注册自定义文件类型
原文地址:http://blog.csdn.net/jiutao_tang/article/details/6563646
事实上有三种方式可以实现文件类型的注册,笔者在网上看到的都是手动实现的或程序实现的,其实也可以直接在工程属性里进行设置。
1. 工程属性定义
项目--->工程属性--->发布--->选项--->文件关联--->设置扩展名、说明、ProgID(自定义)、图标即可。
2. 手工实现文件类型关联
每一个文件类型的信息被保存在注册表中的 'HKEY_CLASSES_ROOT'下面。假设我们自定义的文件类型的后缀为.hyp,文件名为Test_File_Hype (中间不能有空格).
首先在HKEY_CLASSES_ROOT下创建 .hyp
HKEY_CLASSES_ROOT/.hyp
将[默认]键值改为"Test_File_Hype"。然后在HKEY_CLASSES_ROOT下添加主键 Test_File_Hype
HKEY_CLASSES_ROOT/Test_File_Hype
按照下面的路径添加新的主键
HKEY_CLASSES_ROOT/Test_File_Hype/Shell
HKEY_CLASSES_ROOT/Test_File_Hype/Shell/Open
HKEY_CLASSES_ROOT/Test_File_Hype/Shell/Open/Command
将下面的字符作为Command的键值
your application path.exe %1
(例如 C:/WINDOWS/HYP/HYP.EXE %1)
或许你还想为自己的文件类型加上同自己的执行文件一样的图标,很简单,照下面的方法添加就行了。
HKEY_CLASSES_ROOT/Test_File_Hype/DefaultIcon
输入键值:
your application path.EXE,0
后面的零表示文件的图标同程序的主图标一致,如果你的程序有很多图标,换一换数字就可改变文件显
参考:http://www.codesky.net/article/doc/200308/2003082482622669.htm
3. C#编程实现自定义文件类型关联应用程序
在我们自己编写的应用中,经常会用自定义类型的文件的来保存与应用相关的数据,比如.xcf文件就是XCodeFactory应用程序的项目文件。如果没 有向Windows注册表注册该文件类型,那么.xcf文件的图标将是windows的文件默认图标,并且你双击一个a.xcf文件,也不会自动启动 XCodeFactory应用程序来加载a.xcf文件。如何使.xcf文件的图标变成我自己喜爱的图标、如何完成像点击.doc文件就自动打开word 程序的功能,下面将告诉你解决方案。
我们可以通过手动修改注册表来完成上述任务,更好的方式是,通过程序来实现。这样,在安装应用程序时,就可以自动的注册自定义文件类型 了。我通过FileTypeRegister静态类来完成这些功能。首先,将注册需要用到的信息封装成FileTypeRegInfo,定义如下:
public class FileTypeRegInfo
{
/// <summary>
/// 目标类型文件的扩展名
/// </summary>
public string ExtendName; //".xcf"
/// <summary>
/// 目标文件类型说明
/// </summary>
public string Description; //"XCodeFactory项目文件"
/// <summary>
/// 目标类型文件关联的图标
/// </summary>
public string IcoPath;
/// <summary>
/// 打开目标类型文件的应用程序
/// </summary>
public string ExePath;
public FileTypeRegInfo()
{
}
public FileTypeRegInfo(string extendName)
{
this.ExtendName = extendName;
}
}
FileTypeRegister类主要是操作注册表中的内容,实现如下:
/// <summary>
/// FileTypeRegister 用于注册自定义的文件类型。
/// zhuweisky 2005.08.31
/// </summary>
public class FileTypeRegister
{
#region RegisterFileType
/// <summary>
/// RegisterFileType 使文件类型与对应的图标及应用程序关联起来。
/// </summary>
public static void RegisterFileType(FileTypeRegInfo regInfo)
{
if (FileTypeRegistered(regInfo.ExtendName))
{
return;
}
string relationName = regInfo.ExtendName.Substring(1, regInfo.ExtendName.Length - 1).ToUpper() + "_FileType";
RegistryKey fileTypeKey = Registry.ClassesRoot.CreateSubKey(regInfo.ExtendName);
fileTypeKey.SetValue("", relationName);
fileTypeKey.Close();
RegistryKey relationKey = Registry.ClassesRoot.CreateSubKey(relationName);
relationKey.SetValue("", regInfo.Description);
RegistryKey iconKey = relationKey.CreateSubKey("DefaultIcon");
iconKey.SetValue("", regInfo.IcoPath);
RegistryKey shellKey = relationKey.CreateSubKey("Shell");
RegistryKey openKey = shellKey.CreateSubKey("Open");
RegistryKey commandKey = openKey.CreateSubKey("Command");
commandKey.SetValue("", regInfo.ExePath + " %1");
relationKey.Close();
}
/// <summary>
/// GetFileTypeRegInfo 得到指定文件类型关联信息
/// </summary>
public static FileTypeRegInfo GetFileTypeRegInfo(string extendName)
{
if (!FileTypeRegistered(extendName))
{
return null;
}
FileTypeRegInfo regInfo = new FileTypeRegInfo(extendName);
string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType";
RegistryKey relationKey = Registry.ClassesRoot.OpenSubKey(relationName);
regInfo.Description = relationKey.GetValue("").ToString();
RegistryKey iconKey = relationKey.OpenSubKey("DefaultIcon");
regInfo.IcoPath = iconKey.GetValue("").ToString();
RegistryKey shellKey = relationKey.OpenSubKey("Shell");
RegistryKey openKey = shellKey.OpenSubKey("Open");
RegistryKey commandKey = openKey.OpenSubKey("Command");
string temp = commandKey.GetValue("").ToString();
regInfo.ExePath = temp.Substring(0, temp.Length - 3);
return regInfo;
}
/// <summary>
/// UpdateFileTypeRegInfo 更新指定文件类型关联信息
/// </summary>
public static bool UpdateFileTypeRegInfo(FileTypeRegInfo regInfo)
{
if (!FileTypeRegistered(regInfo.ExtendName))
{
return false;
}
string extendName = regInfo.ExtendName;
string relationName = extendName.Substring(1, extendName.Length - 1).ToUpper() + "_FileType";
RegistryKey relationKey = Registry.ClassesRoot.OpenSubKey(relationName, true);
relationKey.SetValue("", regInfo.Description);
RegistryKey iconKey = relationKey.OpenSubKey("DefaultIcon", true);
iconKey.SetValue("", regInfo.IcoPath);
RegistryKey shellKey = relationKey.OpenSubKey("Shell");
RegistryKey openKey = shellKey.OpenSubKey("Open");
RegistryKey commandKey = openKey.OpenSubKey("Command", true);
commandKey.SetValue("", regInfo.ExePath + " %1");
relationKey.Close();
return true;
}
/// <summary>
/// FileTypeRegistered 指定文件类型是否已经注册
/// </summary>
public static bool FileTypeRegistered(string extendName)
{
RegistryKey softwareKey = Registry.ClassesRoot.OpenSubKey(extendName);
if (softwareKey != null)
{
return true;
}
return false;
}
#endregion
}
要注意的是commandKey.SetValue("" ,regInfo.ExePath + " %1") ;其中" %1"表示将被双击的文件的路径传给目标应用程序,这样在双击a.xcf文件时,XCodeFactory才知道要打开哪个文件,所以应用程序的Main方法要被改写为带有参数的形式,就像下面的样子:
[STAThread]
static void Main(string[] args)
{
if ((args != null) && (args.Length > 0))
{
string filePath = "";
for (int i = 0; i < args.Length; i++)
{
filePath += " " + args[i];
}
MainForm.XcfFilePath = filePath.Trim();
}
Application.Run(new MainForm());
}
关于自定义文件类型的注册,本文实现的是最基本的功能,如果需要更多的高级功能,也可以类推实现之。
注:
(1)应用程序的Main方法在Program.cs文件中,可以把原来无参的main方法注释掉;
(2)MainForm就是应用程序的启动窗体,可以改为自己的
(3)filePath.Trim() 就是获取的文件路径了
(4)using Microsoft.Win32; //RegistryKey 位于 Microsoft.Win32 命名空间
(5)注册文件类型后,文件图标可能并不会立即生效(需注销登录或重启Explorer进程)。我们可以采取重启Explorer进程的方式使之立即生效,可参考示例程序中的代码。
我的一个实例:在Form_load事件中进行注册:
private void Form1_Load(object sender, EventArgs e)
{
action = true;
if (!FileTypeRegister.FileTypeRegistered(".hd")) //如果文件类型没有注册,则进行注册
{
FileTypeRegInfo fileTypeRegInfo = new FileTypeRegInfo(".hd"); //文件类型信息
fileTypeRegInfo.Description = "巷道支护系统工程文件";
fileTypeRegInfo.ExePath = Application.ExecutablePath;
fileTypeRegInfo.ExtendName = ".hd";
fileTypeRegInfo.IcoPath = Application.ExecutablePath; //文件图标使用应用程序的
FileTypeRegister fileTypeRegister = new FileTypeRegister(); //注册
FileTypeRegister.RegisterFileType(fileTypeRegInfo);
Process[] process = Process.GetProcesses(); //重启Explorer进程,使更新立即生效
var p = (from proc in process
where proc.ProcessName.Equals("explorer")
select proc).FirstOrDefault();
p.Kill();
}
}
一、Random 生成不重复随机数
转自:http://www.cnblogs.com/huangfr/archive/2012/03/27/2420464.html
命名空间:System
表示伪随机数生成器,一种能够产生满足某些随机性统计要求的数字序列的设备。
伪随机数是以相同的概率从一组有限的数字中选取的。所选数字并不具有完全的随机性,因为它们是用一种确定的数学算法选择的,但是从实用的角度而言,其随机程度已足够了。
伪随机数的生成是从种子值开始。如果反复使用同一个种子,就会生成相同的数字系列。产生不同序列的一种方法是使种子值与时间相关,从而对于 Random 的每个新实例,都会产生不同的系列。默认情况下,Random 类的无参数构造函数使用系统时钟生成其种子值,而参数化构造函数可根据当前时间的计时周期数采用 Int32 值。但是,因为时钟的分辨率有限,所以,如果使用无参数构造函数连续创建不同的 Random 对象,就会创建生成相同随机数序列的随机数生成器。
通过创建单个而不是多个 Random 对象可以避免此问题。
若要提高性能,请创建一个随时间推移能生成多个随机数的 Random 对象,而不要反复新建会生成同一个随机数的 Random 对象。
名称 ● 说明
Equals ● 确定指定的 Object 是否等于当前的 Object。(继承自 Object。)
Finalize ● 允许 Object 在“垃圾回收”回收 Object 之前尝试释放资源并执行其他清理操作。(继承自 Object。)
GetHashCode ● 用作特定类型的哈希函数。(继承自 Object。)
GetType ● 获取当前实例的 Type。(继承自 Object。)
MemberwiseClone ● 创建当前 Object 的浅表副本。(继承自 Object。)
Next ● 已重载。 返回随机数。
NextBytes ● 用随机数填充指定字节数组的元素。
NextDouble ● 返回一个介于 0.0 和 1.0 之间的随机数。
Sample ● 返回一个介于 0.0 和 1.0 之间的随机数。
ToString ● 返回表示当前 Object 的 String。(继承自 Object。)
我们可以使用两种方式初始化一个随机数发生器:
第一种方法不指定随机种子,系统自动选取当前时间作为随机种子:
Random ro = new Random();
第二种方法可以指定一个int型参数作为随机种子:
int iSeed=10;
Random ro = new Random(10);
long tick = DateTime.Now.Ticks;
Random ran = new Random((int)(tick & 0xffffffffL) | (int) (tick >> 32));
这样可以保证99%不是一样。
之后,我们就可以使用这个Random类的对象来产生随机数,这时候要用到Random.Next()方法。这个方法使用相当灵活,你甚至可以指定产生的随机数的上下限。
不指定上下限的使用如下:
int iResult;
iResult=ro.Next();
下面的代码指定返回小于100的随机数:
int iResult;
int iUp=100;
iResult=ro.Next(iUp);
而下面这段代码则指定返回值必须在50-100的范围之内:
int iResult;
int iUp=100;
int iDown=50;
iResult=ro.Next(iDown,iUp);
除了Random.Next()方法之外,Random类还提供了Random.NextDouble()方法产生一个范围在0.0-1.0之间的随机的双精度浮点数:
double dResult;
dResult=ro.NextDouble();
但是用Random类生成题号,会出现重复,特别是在数量较小的题目中要生成不重复的的题目是很难的。
参考了网上的一些方法,找到两类解决方法,一类是通过随机种子入手,使每一次的随机种子不同,来保证不重复;第二类是使用一些数据结构和算法。
下面主要就第二类介绍几个方法:
方法1:思想是用一个数组来保存索引号,先随机生成一个数组位置,然后把随机抽取到的位置的索引号取出来,并把最后一个索引号复制到当前的数组位置,然后使随机数的上限减一,具体如:先把这100个数放在一个数组内,每次随机取一个位置(第一次是1-100,第二次是1-99,...),将该位置的数用最后的数代替。
int[] index = new int[15]; for (int i = 0; i < 15; i++) index = i; Random r = new Random(); //用来保存随机生成的不重复的10个数 int[] result = new int[10]; int site = 15;//设置上限 int id; for (int j = 0; j < 10; j++) { id = r.Next(1, site - 1); //在随机位置取出一个数,保存到结果数组 result[j] = index[id]; //最后一个数复制到当前位置 index[id] = index[site - 1]; //位置的上限减少一 site--; } |
方法2:利用Hashtable。
Hashtable hashtable = new Hashtable(); Random rm = new Random(); int RmNum = 10; for (int i = 0; hashtable.Count < RmNum; i++) { int nValue = rm.Next(100); if (!hashtable.ContainsValue(nValue) && nValue != 0) { hashtable.Add(nValue, nValue); Console.WriteLine(nValue.ToString()); } } |
方法3:递归,用它来检测生成的随机数是否有重复,如果取出来的数字和已取得的数字有重复就重新随机获取。
Random ra=new Random(unchecked((int)DateTime.Now.Ticks)); int[] arrNum=new int[10]; int tmp=0; int minValue=1; int maxValue=10; for (int i=0;i<10;i++) { tmp=ra.Next(minValue,maxValue); //随机取数 arrNum=getNum(arrNum,tmp,minValue,maxValue,ra); //取出值赋到数组中 } ......... ......... public int getNum(int[] arrNum,int tmp,int minValue,int maxValue,Random ra) { int n=0; while (n<=arrNum.Length-1) { if (arrNum[n]==tmp) //利用循环判断是否有重复 { tmp=ra.Next(minValue,maxValue); //重新随机获取。 getNum(arrNum,tmp,minValue,maxValue,ra);//递归:如果取出来的数字和已取得的数字有重复就重新随机获取。 } n++; } return tmp; } |
来源:我和未来有约会
2008-06-17 01:21 by nasa
using System;
using System.Security.Cryptography;
public class RNG
{
private static RNGCryptoServiceProvider rngp = new RNGCryptoServiceProvider();
private static byte[] rb = new byte[4];
/// <summary>
/// 产生一个非负数的乱数
/// </summary>
public static int Next()
{
rngp.GetBytes(rb);
int value = BitConverter.ToInt32(rb, 0);
if (value < 0) value = -value;
return value;
}
/// <summary>
/// 产生一个非负数且最大值在 max 以下的乱数
/// </summary>
/// <param name="max">最大值</param>
public static int Next(int max)
{
rngp.GetBytes(rb);
int value = BitConverter.ToInt32(rb, 0);
value = value % (max + 1);
if (value < 0) value = -value;
return value;
}
/// <summary>
/// 产生一个非负数且最小值在 min 以上最大值在 max 以下的乱数
/// </summary>
/// <param name="min">最小值</param>
/// <param name="max">最大值</param>
public static int Next(int min, int max)
{
int value = Next(max - min) + min;
return value;
}
}
二、线程安全的单例模式
原文地址:http://www.oschina.net/code/snippet_111708_25417
线程安全的单例模式实现有几种思路,个人认为第2种方案最优雅:
1、饿汉式
2、借助内部类
3、普通加锁解决
4、双重检测,但要注意写法
如果单体模式继续扩展为N元单体模式,那就是对象池模式了
饿汉式单例
public
class
Singleton {
private
final
static
Singleton INSTANCE =
new
Singleton();
private
Singleton() { }
public
static
Singleton getInstance() {
return
INSTANCE;
}
}
借助内部类
public
class
Singleton {
private
Singleton() { }
private
static
class
SingletonHolder {
private
final
static
Singleton INSTANCE =
new
Singleton();
}
public
static
Singleton getInstance() {
return
SingletonHolder.INSTANCE;
}
}
属于懒汉式单例,因为Java机制规定,内部类SingletonHolder只有在getInstance()方法第一次调用的时候才会被加载(实现了lazy),而且其加载过程是线程安全的。内部类加载的时候实例化一次instance。
普通加锁解决
public
class
Singleton {
private
static
Singleton instance =
null
;
private
Singleton() { }
public
static
synchronized
Singleton getInstance() {
if
(instance ==
null
) {
instance =
new
Singleton();
}
return
instance;
}
}
虽然解决了线程安全问题,但是每个线程调用getInstance都要加锁,我们想要只在第一次调用getInstance时加锁,请看下面的双重检测方案
双重检测方案
public
class
Singleton {
private
static
Singleton instance =
null
;
private
Singleton() { }
public
static
Singleton getInstance() {
if
(instance ==
null
) {
synchronzied(Singleton.
class
) {
Singleton temp = instance;
if
(temp ==
null
) {
temp =
new
Singleton();
instance = temp
}
}
}
return
instance;
}
}
由于指令重排序问题,所以不可以直接写成下面这样:
public
class
Singleton {
private
static
Singleton instance =
null
;
private
Singleton() { }
public
static
Singleton getInstance() {
if
(instance ==
null
) {
synchronzied(Singleton.
class
) {
if
(instance ==
null
) {
instance =
new
Singleton();
}
}
}
return
instance;
}
}
但是如果instance实例变量用
volatile
修饰就可以了,
volatile
修饰的话就可以确保instance =
new
Singleton();对应的指令不会重排序,如下的单例代码也是线程安全的:
public
class
Singleton {
private
static
volatile
Singleton instance =
null
;
private
Singleton() { }
public
static
Singleton getInstance() {
if
(instance ==
null
) {
synchronzied(Singleton.
class
) {
if
(instance ==
null
) {
instance =
new
Singleton();
}
}
}
return
instance;
}
}
以下转自:http://www.cnblogs.com/akwwl/p/3240813.html
1.添加命名空间
System.IO;
System.Text;
2.文件的读取
(1).使用FileStream类进行文件的读取,并将它转换成char数组,然后输出。
byte[] byData = new byte[100]; char[] charData = new char[1000]; public void Read() { try { FileStream file = new FileStream("E:\\test.txt", FileMode.Open); file.Seek(0, SeekOrigin.Begin); file.Read(byData, 0, 100); //byData传进来的字节数组,用以接受FileStream对象中的数据,第2个参数是字节数组中开始写入数据的位置,它通常是0,表示从数组的开端文件中向数组写数据,最后一个参数规定从文件读多少字符. Decoder d = Encoding.Default.GetDecoder(); d.GetChars(byData, 0, byData.Length, charData, 0); Console.WriteLine(charData); file.Close(); } catch (IOException e) { Console.WriteLine(e.ToString()); } }
(2).使用StreamReader读取文件,然后一行一行的输出。
public void Read(string path) { StreamReader sr = new StreamReader(path,Encoding.Default); String line; while ((line = sr.ReadLine()) != null) { Console.WriteLine(line.ToString()); } }
3.文件的写入
(1).使用FileStream类创建文件,然后将数据写入到文件里。
public void Write() { FileStream fs = new FileStream("E:\\ak.txt", FileMode.Create); //获得字节数组 byte[] data = System.Text.Encoding.Default.GetBytes("Hello World!"); //开始写入 fs.Write(data, 0, data.Length); //清空缓冲区、关闭流 fs.Flush(); fs.Close(); }
(2).使用FileStream类创建文件,使用StreamWriter类,将数据写入到文件。
public void Write(string path) { FileStream fs = new FileStream(path, FileMode.Create); StreamWriter sw = new StreamWriter(fs); //开始写入 sw.Write("Hello World!!!!"); //清空缓冲区 sw.Flush(); //关闭流 sw.Close(); fs.Close(); }
以上就完成了,txt文本文档的数据读取与写入。
[转]C#获取本机IP搜集整理7种方法
①
1 private void GetIP() 2 { 3 string hostName = Dns.GetHostName();//本机名 4 //System.Net.IPAddress[] addressList = Dns.GetHostByName(hostName).AddressList;//会警告GetHostByName()已过期,我运行时且只返回了一个IPv4的地址 5 System.Net.IPAddress[] addressList = Dns.GetHostAddresses(hostName);//会返回所有地址,包括IPv4和IPv6 6 foreach (IPAddress ip in addressList) 7 { 8 listBox1.Items.Add(ip.ToString()); 9 } 10 }
②使用IPHostEntry获取本机局域网地址
1 static string GetLocalIp() 2 { 3 string hostname = Dns.GetHostName();//得到本机名 4 //IPHostEntry localhost = Dns.GetHostByName(hostname);//方法已过期,只得到IPv4的地址 5 <SPAN style="WHITE-SPACE: pre"> </SPAN> IPHostEntry localhost = Dns.GetHostEntry(hostname); 6 IPAddress localaddr = localhost.AddressList[0]; 7 return localaddr.ToString(); 8 }
方法时通过向网站向一些提供IP查询的网站发送webrequest,然后分析返回的数据流
1 string strUrl = "提供IP查询的网站的链接"; 2 Uri uri = new Uri(strUrl); 3 WebRequest webreq = WebRequest.Create(uri); 4 Stream s = webreq .GetResponse().GetResponseStream(); 5 StreamReader sr = new StreamReader(s, Encoding.Default); 6 string all = sr.ReadToEnd(); 7 int i = all.IndexOf("[") + 1; 8 //分析字符串得到IP 9 return ip; 10 /* 11 我用的是http://www.ip.cn/getip.php?action=getip&ip_url=&from=web 12 (这种链接很容易找的,百度“IP”得到一些网站,分析一下网站的链接就能得到) 13 返回的数据是: 14 <div class="well"><p>当前 IP:<code>0.0.0.0</code> 来自:XX省XX市 电信</p><p>GeoIP: Beijing, China</p></div> 15 解析这段就行 16 */
⑥通过获取CMD里ipconfig命令的结果来得到IP
1 private void GetIP6() 2 { 3 Process cmd = new Process(); 4 cmd.StartInfo.FileName = "ipconfig.exe";//设置程序名 5 cmd.StartInfo.Arguments = "/all"; //参数 6 //重定向标准输出 7 cmd.StartInfo.RedirectStandardOutput = true; 8 cmd.StartInfo.RedirectStandardInput = true; 9 cmd.StartInfo.UseShellExecute = false; 10 cmd.StartInfo.CreateNoWindow = true;//不显示窗口(控制台程序是黑屏) 11 //cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;//暂时不明白什么意思 12 /* 13 收集一下 有备无患 14 关于:ProcessWindowStyle.Hidden隐藏后如何再显示? 15 hwndWin32Host = Win32Native.FindWindow(null, win32Exinfo.windowsName); 16 Win32Native.ShowWindow(hwndWin32Host, 1); //先FindWindow找到窗口后再ShowWindow 17 */ 18 cmd.Start(); 19 string info = cmd.StandardOutput.ReadToEnd(); 20 cmd.WaitForExit(); 21 cmd.Close(); 22 textBox1.AppendText(info); 23 }
⑦NetworkInformation
以下转自:http://www.cnblogs.com/huashanlin/archive/2007/07/07/809305.html
[STAThread]的含义
Posted on 2007-07-07 10:06 桦林 阅读(32335) 评论(10) 编辑 收藏[STAThread]
STAThread:Single Thread Apartment Thread.(单一线程单元线程)
[]是用来表示Attributes;
[STAThread]
是一种线程模型,用在程序的入口方法上(在C#和VB.NET里是Main()方法),来指定当前线程的ApartmentState 是STA。用在其他方法上不产生影响。在aspx页面上可以使用AspCompat = "true" 来达到同样的效果。这个属性只在 Com Interop 有用,如果全部是 managed code 则无用。简单的说法:[STAThread]指示应用程序的默认线程模型是单线程单元 (STA)。启动线程模型可设置为单线程单元或多线程单元。如果未对其进行设置,则该线程不被初始化。也就是说如果你用的.NET Framework,并且没有使用COM Interop,一般不需要这个Attribute。其它的还有MTA(多线程套间)、Free Thread(自由线程)。
[STAThread] attribute指示应用程序的 COM 线程模型是单线程单元。
而于此对应的多线程单元则是 [MTAThread] (多线程单元线程)
COM 线程模型只适用于使用 COM interop 的应用程序。如果将此属性应用到不使用 COM interop 的应用程序,将没有任何效果。
COM 线程模型可设置为单线程单元或多线程单元。如果应用程序线程实际调用了 COM 组件,则仅为 COM interop 初始化该线程。如果没有使用 COM interop,则不初始化该线程。
以下是找到的一个资料介绍:
Q. When I create a c# project from scratch in VS.NET, the generated code always have a [STAThread] attribute above the main routine. What does the STAThread attribute really do? Can I change it to MTAThread instead? I have searched website and books, no one seems to explain this well.
Asked by anon. Answered by the Wonk on February 17, 2003
A.
The STAThreadAttribute marks a thread to use the Single-Threaded COM Apartment if COM is needed. By default, .NET won't initialize COM at all. It's only when COM is needed, like when a COM object or COM Control is created or when drag 'n' drop is needed, that COM is initialized. When that happens, .NET calls the underlying CoInitializeEx function, which takes a flag indicating whether to join the thread to a multi-threaded or single-threaded apartment.
A multi-threaded apartment (MTA) in COM is more efficient, since any of a number of RPC threads from a pool can be used to handle a request. However, an object on the MTA thread needs to protect itself from multiple threads accessing it at the same time, so that efficiency comes at a cost.
The single-thread apartment (STA) in COM is inherently single-threaded and therefore no additional thread synchronization is needed. The STA is implemented using the thread's Windows message queue, which is how requests to objects on an STA are serialized. Because of how the STA thread is implemented, calls to objects on that thread are serialized with Windows message handling on that thread, making sure that everything, both the COM objects and the underlying windowing objects, e.g. HWNDs, are all synchronized. This is necessary for UI-oriented COM objects, like controls and drag 'n' drop, which must also be synchronized together with the UI.
When COM is needed .NET will call CoInitializeEx, picking the MTA by default because it's more efficient. However, to get the synchronization needed for controls, windows and drag 'n' drop, you need to mark a thread's entry point with the STAThreadAttribute to let .NET know to initialize the UI thread on the STA. All of the VS.NET project templates put that attribute in to make sure you don't forget:
大致意思是:由于很多COM在.NET环境下如果使用多线程的话,会导致引用的COM不能正常运行,而如果不声明程序为STAThread的话,.NET就会自动使用多线程来提高效率,这样就会导致不可预知的后果。
以下引用另一同辈的发言:http://blog.csdn.net/qilang/archive/2006/06/06/775605.aspx
STA不是单线程的意思.英文为single threaded apartment.是一种套间(或译为公寓)线程模式.
sta thread并不表明应用程式的类型,和应用程序不搭界,恰相反,一个应用程序可以有多个线程.每个线程也可以有多个组件或对象.以前win16位系统的组件线程模式才真正是单线程.这是一种被淘汰了的模式.
线程模式用于处理组件在多线程的环境里并行与并互的方式.比如套间线程(STAThread)模式中接口跨线程传递必须被调度(Marshal),不调度直传肯定会失败!而MTA或FreeThread模式中的接口可以不经调度直接传递.
这种调度在特定的环境中非常影响性能(可有几百倍之差).如VB里只支持STAThread模式.FreeThread模式的组件会在里面表现成和跨进程一样慢!
线程模式是微软的COM基础中的极其重要的概念.一定要吃透!
我对.net真是一窍不通(没空去弄,对不起微软去年的奖赏).但我可以肯定,C#中的[STAThread]属性是应用程序的套间初始化代码.可以直接理解成SDK里的
CoInitialize(NULL);
初始一个STA套间实际上是相当于开了一个消息窗口,所有调用经此窗口过程调度到组件内.
同理[MTAThread](不知有没有这个属性,自已去查)
可以理解成
CoInitializeEx(NULL,COINIT_MULTITHREADED )
这经常是一个对初入com大门的人来说,有一定难度但必须过的一道关.