第一篇:总结C#获取当前路径的7种方法
总结C#获取当前路径的7种方法
C#获取当前路径的方法如下:
1.System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName -获取模块的完整路径。
2.System.Environment.CurrentDirectory -获取和设置当前目录(该进程从中启动的目录)的完全限定目录。3.System.IO.Directory.GetCurrentDirectory()-获取应用程序的当前工作目录。这个不一定是程序从中启动的目录啊,有可能程序放在C:www.xiexiebang.comLOCALS~1Temp
System.Environment.GetEnvironmentVariable(“TEMP”)=C:DOCUME~1zhoufoxcnLOCALS~1Temp
System.Environment.GetEnvironmentVariable(“Path”)=C:WINDOWSsystem32;C:WINDOWS;C:WINDOWSSystem32Wbem;C:jdk1.5.0bin;C:MySQLServer5.0bin;C:Program FilesSymantecpcAnywhere;C:Program FilesMicrosoft SQL Server80ToolsBINN
C# 相对路径 系统路径 2007-12-22 09:53 //获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。
string
str5=Application.StartupPath;//可获得当前执行的exe的文件名。
string
str1
=Process.GetCurrentProcess().MainModule.FileName;//获取和设置当前目录(即该进程从中启动的目录)的完全限定路径。备注
按照定义,如果该进程在本地或网络驱动器的根目录中启动,则此属性的值为驱动器名称后跟一个尾部反斜杠(如“C:”)。如果该进程在子目录中启动,则此属性的值为不带尾部反斜杠的驱动器和子目录路径(如“C:mySubDirectory”)。
string
str2=Environment.CurrentDirectory;//获取应用程序的当前工作目录。
string
str3=Directory.GetCurrentDirectory();//获取基目录,它由程序集冲突解决程序用来探测程序集。
string
str4=AppDomain.CurrentDomain.BaseDirectory;//获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。
string
str5=Application.StartupPath;//获取启动了应用程序的可执行文件的路径,包括可执行文件的名称。
string
str6=Application.ExecutablePath;//获取或设置包含该应用程序的目录的名称。
string
str7=AppDomain.CurrentDomain.SetupInformation.ApplicationBase;//例子
Application.StartupPath;//可以得到F:learningc#TrainingwinwinbinDebug //注意自己补两个 Application.StartupPath+“3.jpg”;
FilesMicrosoft Visual
在c#中,相对路径是用“.”和“..”表示,“.”代表当前目录,“..”代表上一级录。
例如 假设我用vs2005在D:My DocumentsVisual Studio 2005Projects目录里创建了一个名叫controls的项目,即在Projects文件夹里有一个controls文件夹,controls文件夹里有三个文件:controls.sln
controls文件夹
GulfOfStLawrence文件夹。
D:My DocumentsVisual Studio 2005ProjectsControlsControlsbinDebug是这个简单项目能够运行的可执行文件Controls.exe
现在我想要 D:My DocumentsVisual Studio 2005ProjectsControlsGulfOfStLawrence文件夹下的Gulf_of_St._Lawrence.mxd(arcgis desktop)工程文件路径。
那么相对路径应该就是“......GulfOfStLawrenceGulf_of_St._Lawrence.mxd” 即string filename = @“......GulfOfStLawrenceGulf_of_St._Lawrence.mxd”;
心得:1.用相对路径能增加项目的可移植性。使一个工程在移植过程中变得简单,节省了大量布置与工程相关的文件的时间。(如果设置的是绝对路径)。
2.使用相对路径也使程序代码变得简单
3.但有一点必须注意:(只能在同一个驱动器里(如:都在D:里)使用相对路径)。
第二篇:C#总结
引用类型是类型安全的指针,它们的内存是分配在堆(保存指针地址)上的。String、数组、类、接口和委托都是引用类型。
强制类型转换与as类型转换的区别:当类型转换非法时,强制类型转换将抛出一System.InvalidCastException异常,而as不会抛出异常,它返回一个null值。用using创建别名:using console = System.Console;访问限定符:
public 该成员可以被其他任何类访问 protected 该成员只能被其派生类访问
private 该成员只能被本类的其他成员访问 internal 该成员只能在当前编译单元的其他成员访问 带参数列表和返回值的Main方法: class Test {
public static int Main(string[] args)
{
foreach(string arg in args)
{
...}
} } 构造函数(constructor)包括实例构造函数和静态构造函数。构造函数与类名相同,且不能有返回值。例:
class TestClass {
TestClass()//实例构造函数:可以访问静态成员和实例成员,用于初始化实例成员
{
...}
static TestClass()//静态构造函数:只能访问静态成员,用于初始化静态成员
{
...} } 类的静态成员属于类所有,不必生成实例就可以访问,它是在载入包含类的应用程序时创建的,但静态方法不能访问类的实例变量和方法。通常,静态变量是在定义时就赋初始值的。类的实例成员属于类的实例所有,不创建实例对象就无法对其进行访问,实例成员可以访问类的
静态成员和其它实例成员。调用基类的析构函数: class A {
public A()
{
...} } class B {
public B(): base()//调用基类的析构函数
{
...} } 常量:其值是在编译时设定的,必须是数值文字。默认状态下常量是静态的。例: class A {
public const double pi = 3.1415;} 常量是编译时就确定的值,只读字段是在运行才能确定的值。比如运行时才能确定的屏幕分辨率。
只读字段只能在类的析构函数中赋值。静态只读字段: class A {
public static readonly int ScreenWidth;//静态只读字段
static A()
//静态析构函数
{
ScreenWidth = 1024;//在静态析构函数中初始化
} } 在类的继承中,类的析构函数是不会被继承的。一个派生类只能从一个基类继承,不能同时从多个基类继承,但可以通过继承多个接口来达到相同目的。实现多继承的唯一方法就是使用接口。例:
class MyFancyGrid: Control, ISerializable, IDataBound {...} 密封类是不能继承的类,抽象类不能被定义为密封类,且密封类的私有成员不能用protected修饰,只能用private。例: sealed class A {...} 关键字ref和out用于指定用引用方式传递方法的参数。
它们的区别是:ref参数必须初始化,而out参数不需要初始化。所以在方法处理代码依赖参数的初始化值时使用ref,不依赖初始化值时使用out。对out参数即使在传递前对其进行了初始化,其值也不会传递到方法处理函数内部。传递时系统会将其设为未初始化。所以在方法内部必须对out参数进行初始化。
方法重载时,必须参数数目和参数类型其中之一不同,返回值不同不能作为重载。C#不支持方法的默认值,只能通过方法重载来实现。例: class A {
int Method(int a)
{
...}
void Method(int a, int b)//参数数目不同
{
//返回值不同不能作为重载
...} } params参数用于一个不定数目参数的方法,一般后面跟一个数组。例: class A {
public void Method(params int[] i)
{
...} } 方法的覆盖:指派生类覆盖基类的同名方法,有二种方法
1)第一种是在派生类要覆盖的方法前面加new修饰,而基类不需要作任何改动。这种方法的缺点是不能实现多态。例: class A {
public void Method()//无需任何修饰
{
...} } class B: A
//从基类继承
{
new public void Method()//覆盖基类的同名方法
{
...} } class TestClass {
A Instance = new B();
Instance.Method();//这时将调用类A的Method方法,而不是类B的Method方法 } 2)第二种是在派生类要覆盖的方法前面加override修饰,而基类的同名方法前面加virtual修饰。这样就能实现多态,例: class A {
virtual public void Method()
//基类定义虚方法
{
//虚拟方法不能定义为private,因为private成员对派生类是无法访问的...} }
class B: A
//从基类继承 {
override public void Method()
//派生类覆盖基类的同名虚方法
{
...} } class TestClass {
protected void Test()
{
A Instance = new B();
//定义一个实例,类型为基类,从派生类创建
//派生类总是能够向上转换为其基类
Instance.Method();
//将调用派生类B的Method方法,而不是基类的,这就是多态
} } 说明:new修饰的方法覆盖不能实现多态的原因,是因为使用new时编译器只会实现早期绑定(early binding)。即调用的方法在编译时就决定了:编译器看到Instance.Method()而Instance的类是A,就会调用类A的Method()方法。
override修饰的方法覆盖可以实现多态的原因,是因为实现了后期绑定(late binding)。使用override时强制编译器在运行时根据类的真正类型正确调用相应的方法,而不是在编译时。
而基类的同名方法必须加virtual修饰。
类的静态方法可能通过 类名.静态方法名 这种格式来调用,不能使用 实例名.静态方法名 这种方法调用。
因为类的静态方法为类所有(是属于类本身的),而非实例所有(不是属于类的实例的)。类的静态方法可以访问类的任何静态成员,但不能访问类的实例成员。C#中类的变量称为字段。类的public变量称为类的公共字段。
类的属性由一个protected(也可以是private)字段和getter和setter方法构成: class Address {
protected string zipCode;//protected字段,注意大小写
public string ZipCode
{
get
//getter方法
{
return zipCode;
}
set
//setter方法
{
zipCode = value;//被传递的值自动被在这个value变量中
}
};} 只读属性是指省略setter方法的属性,只读属性只能读取,不能设置。
属性也可以用限定符virtual,override和abstract修饰,功能同其他类的方法。
属性有一个用处称为懒惰的初始化(lazy initialization)。即在需要类成员时才对它们进行初始化。如果类中包含了很少被引用的成员,而这些成员的初始化又会花费大量的时候和系统资源的话,懒惰的初始化就很有用了。C#中数组对象共同的基类是System.Array。将数组声明为类的一个成员时,声明数组与实例化数组必须分开,这是因为只能在运行时创建了类的实例对象之后,才能实例化数组元素值。声明:
int[] intArray;//一维数组 int[,] int3Array;//三维数组 初始化:
intArray = new int[3] {1,2,3};int[,] int2Array = new int[2,3] {{1,2,3},{4,5,6}};//声明时可以初始化 遍历:
1)一维数组
for(int i = 0;i < intArray.Length;i++);//Array.Length返回数组所有元素的个数 foreach(int i in intArray);for(int i = 0;i < intArray.GetLength(0);i++);//Array.GetLength(0)返回数组第一维的个数 2)多维数组
for(int i = 0;i < int3Array.GetLength(0);i++)//遍历三维数组
for(int j = 0;j < int3Array.GetLength(1);j++)
for(int k = 0;k < int3Array.GetLength(2);k++)
{
...} 数组的维数就是该数组的秩(Rank)。Array.Rank可以返回数据的秩。锯齿数组(jagged Array)是元素为数组的数组,例:
int[][] jaggedArray = new int[2][];//包含二个元素,每个元素是个数组 jaggedArray[0] = new int[2];//每个元素必须初始化 jaggedArray[1] = new int[3];for(int i = 0;i < jaggedArray.Length;i++)//遍历锯齿数组
for(int j = 0;j < jaggedArray[i].Length;j++)
{
...} 类的属性称为智能字段,类的索引器称为智能数组。由于类本身作数组使用,所以用this作索引器的名称,索引器有索引参数值。例: using System;using System.Collections;class MyListBox {
protected ArrayList data = new ArrayList();
public object this[int idx] //this作索引器名称,idx是索引参数
{
get
{
if(idx >-1 && idx < data.Count)
{
return data[idx];
}
else
{
return null;
}
}
set
{
if(idx >-1 && idx < data.Count)
{
data[idx] = value;
}
else if(idx = data.Count)
{
data.Add(value);
}
else
{
//抛出一个异常
}
}
} } 接口是二段不同代码之间约定,通过约定实现彼此之间的相互访问。C#并不支持多继承,但通过接口可实现相同功能。当在接口中指定了实现这个接口的类时,我们就称这个类“实现了该接口”或“从接口继承”。一个接口基本上就是一个抽象类,这个抽象类中除了声明C#类的其他成员类型——例如属性、事件和索引器之外,只声明了纯虚拟方法。接口中可以包含方法、属性、索引器和事件——其中任何一种都不是在接口自身中来实现的。例:
interface IExampleInterface {
//property declaration
int testProperty { get;}
//event declaration
event testEvevnt Changed;
//mothed declaration
function void testMothed();
//indexer declaration
string this[int index] { get;set;} } 说明:定义接口时,在方法、属性、事件和索引器所有这些接口成员都不能用public之类的访问限定符,因为所有接口成员都是public类型的。因为接口定义了一个约定,任何实现一个接口的类都必须定义那个接口中每一个成员,否则将编译失败。例: using System;public class FancyControl {
protected string data;
public string Data
{
get {return this.data;}
set {data = value;}
} } interface IValidate {
bool Validate();//接口方法
} public class MyControl: FancyControl, IValidate {
public MyControl()
{
data = “my control data”;
}
public bool Validate()//实现接口
{
if(data == “my control data”)
return true;
else
return false;
} } class InterfaceApp {
MyControl myControl = new MyControl();
IValidate val =(IValidate)myControl;//可以将一个实现某接口的类,转换成该接口
bool success = val.Validate();//然后可调用该接口的方法 } 也可以用:bool success = myControl.Validate();这种方法来调用Validate方法,因为Validate在类MyControl中是被定义成public的,如果去除public,Validate方法被隐藏,就不能用这种方法调用了,这样隐藏接口方法称为名字隐藏(name hiding)。可以用:类实例 is 接口名 来判断某个类是否实现了某接口,例: myControl is IValidate //MyControl类的实例myControl是否实现了IValidate接口
当然,也可用as来作转换,根据转换结果是否为null来判断某个类是否实现了某接口,例: IValidate val = myControl as IValidate;if(null == val){...//没有实现IValidate接口 } else {...//实现了IValidate接口
}
如果一个类从多个接口继承,而这些接口中如果定义的同名的方法,则实现接口的方法时,必须加接口名来区别,写成 接口名.方法名。假设Test类从IDataStore和ISerializable二个接口继承,而这二个接口都有SaveData()方法,实现SaveData()方法时必须写成: class Test: ISerializable, IDataStore {
void ISerializable.SaveData()
{
...}
void IDataStore.SaveData()
{
...} } 如果一个类从多个接口继承,为了方便可以定义一个新的接口,这个接口继续多个接口,然后类直接从这个接口继承就可以了,这个叫合并接口。例: interface ISaveData: ISerializable, IDataStore { //不需要定义任何方法或成员,只是用作合并 } class Test: ISaveData //只要继承ISaveData就可以了 {...} C# 操作符优先级(从高到低)
初级操作符()x.y f(x)a[x] x++ x--new typeof sizeof checked unchecked 一元操作符 +位移操作符 << >> 关系操作符 < > <= >= is 等于操作符 == 逻辑与
& 逻辑异或 ^ 逻辑或
| 条件与
&& 条件或
|| 条件操作符 ?: 赋值操作符 = *= /= %= +=-= <<= >>= &= ^= |= 所有的二元操作符除赋值符外都是左联合的,即从左到右计算。
typeof()运算符可以从一个类名得到一个System.Type对象,而从System.Object对象继承来的GetType()方法则可从一个类实例来得到一个System.Type对象。例: Type t1 = typeof(Apple);//Apple是一个类名
Apple apple = new Apple();//apple是Apple类的一个实例 Type t2 = apple.GetType();//t1与t2是相同的 通过反射得到一个类的所有成员和方法: Type t = typeof(Apple);string className = t.ToString();//得到类名
MethodInfo[] methods = t.GetMethods();//得到所有方法 foreach(MethodInfo method in methods){ //用method.ToString()得到方法名 } MemberInfo[] members = t.GetMembers();//得到所有成员 foreach(MemberInfo member in members){ //用member.ToString()得到成员名 } sizeof()操作符用来计算值类型变量在内存中占用的字节数(Bytes),并且它只能在unsafe(非安全)
代码中使用。例:
static unsafe public void ShowSizes(){
int i, j;
j = sizeof(short);
j = sizeof(i);} 尽可能使用复合赋值操作符,它比不用复合赋值操作符的效率高。for语句的语法为:
for(initialization;Boolean-expression;step)
embedded-statement 在initialization和step部份还可以使用逗号操作符,例: for(int i = '0', j = 1;i <= 'xFF';i++, j++)for(int i = 1, j = 1;i < 1000;i += j, j = i!~ ++--true false 二元:+32)/ 9)* 5;
} } 代表的(delegate)目的与C++中的函数指针相同,代表不是在编译时被定义的,而是在运行时被定义的。
代表主要有二个用途:回调(Callback)和事件处理(event)回调通常用于异步处理和自定义处理。例: class DBManager {
static DBConnection[] activeConnections;
//声明回调函数
public void delegate EnumConnectionCallback(DBConnection connection);
public static void EnumConnections(EnumConnectionCallback callback)
{
foreach(DBConnection connection in activeConnections)
{
callback(connection);//执行回调函数
}
} } //调用
class DelegateApp {
public static void ActiveConncetionCallback(DBConnection connection)//处理函数
{
...}
public void main()
{
//创建指向具体处理函数的代表实例(新建一个代表,让它指向具体的处理函数)
DBManager.EmnuConnectionCallback myCallback = new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);
DBManager.EnumConnections(myCallback);
} } //使用静态代表,上面的调用改为 class DelegateApp {
//创建一个指向处理函数的静态代表
public static DBManager.EmnuConnectionCallback myCallback
= new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);
public static void ActiveConncetionCallback(DBConnection connection)
{...} public void main()
{
DBManager.EnumConnections(myCallback);
} } //在需要时才创建代表,上面的调用改为
class DelegateApp {
//将创建代表放在属性的getter方法中
public static DBManager.EmnuConnectionCallback myCallback
{
get
{
retun new DBManager.EmnuConnectionCallback(ActiveConncetionCallback);
}
}
public static void ActiveConncetionCallback(DBConnection connection)
{...} public void main()
{
DelegateApp app = new DelegateApp();//创建应用程序
DBManager.EnumConnections(myCallback);
} } 可以将多个代表整合成单个代表,例: class CompositeDelegateApp {
public static void LogEvent(Part part)
{
...}
public static void EmailPurchasingMgr(Part part)
{
...}
public static void Main()
{
//定义二个代表
InventoryManager.OutOfStockExceptionMethod LogEventCallback
= new InventoryManager.OutOfStockExceptionMethod(LogEvent);
InventoryManager.OutOfStockExceptionMethod EmailPurchasingMgrCallback
= new InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr);
//整合为一个代表,注意后加的代表先执行(这里是先执行LogEventCallback)
InventoryManager.OutOfStockExceptionMethod onHandExceptionEventsCallback
= EmailPurchasingMgrCallback + LogEventCallback;
//调用代表
InventoryManager mgr = new InventoryManager();
mgr.ProcessInventory(onHandExceptionEventsCallback);
//InventoryManager类的ProcessInventory方法的原型为:
//public void ProcessInventory(OutOfStockExceptionMethod exception);
} } 可以根据需要将多个代表自由地组合成单个代表,例: class CompositeDelegateApp {
//代表指向的处理函数(三个代表三个函数)
public static void LogEvent(Part part)
{
...} public static void EmailPurchasingMgr(Part part){...}
public static void EmailStoreMgr(Part part)
{
...}
public static void Main()
{
//通过数组定义三个代表
InventoryManager.OutOfStockExceptionMethod[] exceptionMethods
= new InventoryManager.OutOfStockExceptionMethod[3];
exceptionMethods[0] = new InventoryManager.OutOfStockExceptionMethod(LogEvent);
exceptionMethods[1] = new InventoryManager.OutOfStockExceptionMethod(EmailPurchasingMgr);
exceptionMethods[2] = new InventoryManager.OutOfStockExceptionMethod(EmailStoreMgr);
int location = 1;
//再定义一个代表(用于组合成单代表)
InventoryManager.OutOfStockExceptionMethod compositeDelegate;
//根据需要组合
if(location = 2)
{
compositeDelegate = exceptionMethods[0] + exceptionMethods[1];
}
else
{
compositeDelegate = exceptionMethods[0] + exceptionMethods[2];
}
//调用代表
InventoryManager mgr = new InventoryManager();
mgr.ProcessInventory(compositeDelegate);
} } C#的事件遵循“发布——预订”的设计模式。在这种模式中,一个类公布能够出现的所有事件,然后任何的类都可以预订这些事件。一旦事件产生,运行环境就负责通知每个订户事件已经发生了。
当代表作为事件的处理结果时(或者说定义具有代表的事件),定义的代表必须指向二个参数的方法:一个参数是引发事件的对象(发布者),另一个是事件信息对象(这个对象必须从EventArgs类中派生)。例: using System;
class InventoryChangeEventArgs: EventArgs //事件信息对象,从EventArgs类派生 {...//假设定义二个public属性string Sku和int Change } class InventoryManager
//事件的发布者 {
//声明代表
public delegate void InventoryChangeEventHander(object source, InventoryChangeEventArgs e);
//发布事件,event关键字可将一个代表指向多个处理函数
public event InventoryChangeEventHandler onInventoryChangeHander;
public void UpdateInventory(string sku, int change)
{
if(change == 0)
return;
InventoryChangeEventArgs e = new InventoryChangeEventArgs(sku, change);
//触发事件
if(onInventoryChangeHandler!= null)//如果有预订者就触发
onInventoryChangeHandler(this, e);//执行代表指向的处理函数
} } class InventoryWatcher
//事件的预订者 {
public InventoryWatcher(InventoryManager mgr)//mgr参数用于联结发布者
{
this.inventoryManager = mgr;
//预订事件,用 += 调用多个处理函数
mgr.onInventroyChangeHandler += new InventoryManager.InventoryChangeEventHandler(onInventoryChange);
//事件处理函数
void onInventroyChange(object source, InventroyChangeEventArgs e)
{
...}
InventoryManager inventoryManager;
} } class EventsApp
//主程序 {
public static void Main()
{
InventoryManager inventoryManager = new InventoryManager();
InventoryWatcher inventoryWatcher = new InventoryWatcher(inventoryManager);
inventoryManager.UpdateInventory(“111 006 116”,-2);
inventoryManager.UpdateInventory(“111 006 116”, 5);
} } Microsoft Windows NT和IBM OS/2等操作系统都支持占先型多任务。在占先型多任务执行中,处理器负责
给每个线程分配一定量的运行时间——一个时间片(timeslice)。处理器接着在不同的线程之间进行切换,执行相应的处理。在单处理器的计算机上,并不能真正实现多个线程的同时运行,除非运行在多个处理器 的计算机上。操作系统调度的多线程只是根据分配给每个线程时间片进行切换执行,感觉上就像同时执行。
上下文切换(context switching)是线程运行的一部分,处理器使用一个硬件时间来判断一个指定线程的时间片何时结束。当这个硬件计时器给出中断信号时,处理器把当前运行的线程所用的所有寄存器(registers)数据存储到堆栈中。然后,处理器把堆栈里那些相同的寄存器信息存放到一种被称为“上下文结构”的数据结构中。当处理器要切换回原来执行的线程时,它反向执行这个过程,利用与该线程相关的上下文结构,在寄存器里重新恢复与这一线程相关的信息。这样的一个完整过程称为“上下文切换”。多线程允许应用程序把任务分割为多个线程,它们彼此之间可以独立地工作,最大限度地利用了处理器时间。using System;using System.Threading;class SimpleThreadApp {
public static void WorkerThreadMethod()//线程的执行体
{
...//执行一些操作
}
public static void Main()
{
//创建一个线程代表指向线程的执行体,ThreadStart是创建新线程必须用到的代表
ThreadStart worker = new ThreadStart(WorkerThreadMethod);
Thread t = new Thread(worker);//用线程代表创建线程
t.Start();
//执行线程
} } 可以通过两种方式来得到一个Thread对象:一种是通过创建一个新线程来得到,如上例;另一种在正在执行的线程调用静态的Thread.CurrentThread方法。
静态方法Thread.Sleep(int ms)可以让当前线程(它自动调用Thread.CurrentThread)暂停指定毫秒的时间。
如果使用Thread.Sleep(0)那么当前线程将一直处于等待中,直到另一个线程调用这个线程的实例方法Thread.Interrupt方法,等待才会结束。使用Thread.Suspend方法也能挂起线程,Thread.Suspend方法可以被当前线程或其他线程调用,而Thread.Sleep(0)只能由当前线程在执行体中调用。当线程用Thread.Suspend挂起时,必须用Thread.Resume方法恢复。不论Thread.Suspend方法调用了多少次,只要调用Thread.Resume方法一次就可以线程恢复执行。用Thread.Suspend方法并不会阻塞线程,调用立即返回。而Thread.Sleep(0)则会阻塞线程。所以确切地说Thread.Sleep(0)暂停线程,而不是挂起线程。
使用Thread.Abort方法可以终止正在执行的线程。当Thread.Abort方法被调用时,线程不会立即终止执行。运行环境将会等待,直到线程到达文档中所描述的“安全点”。如果要确保线程已经完全停止,可以使用Thread.Join方法。这是一个同步调用,同步调用意味着直到线程完全停止,调用才会返回。
Thread.Priority属性用于设置的线程的优先级。其值是Thread.ThreadPriority枚举值,可以设为Highest, AboveNormal,Normal, BelowNormal, Lowest。缺省值是Thread.ThreadPriority.Normal。
线程的同步是为了解决多个线程同时使用同一对象产生的一些问题。通过同步,可以指定代码的临界区(critical section),一次只有一个线程可以进入临界区。使用System.Monitor类(锁定与信号量)进行线程同步: using System;using System.Threading;public void SaveData(string text)//线程执行函数或线程执行函数调用的对象的方法 {
...//执行其他一些不需要同步的处理
Monitor.Enter(this);//获取对象的Monitor锁
...//执行需要同步的处理
Monitor.Exit(this);//释放对象的Monitor锁
...//执行其他一些不需要同步的处理
} 说明:当执行Monitor.Enter方法时。这个方法会试图获取对象上的Monitor锁,如果另一个线程已经拥有了这个锁,这个方法将会阻塞(block),直到这个锁被释放。
也可用C#的lock语句来获得和释放一个Monitor锁。上面同步写成:public void SaveData(string text)//线程执行函数或线程执行函数调用的对象的方法 {
...//执行其他一些不需要同步的处理
lock(this)//获取对象的Monitor锁,代码块执行完成后释放Monitor锁
{
...//执行需要同步的处理
}
...//执行其他一些不需要同步的处理 } 也可以使用System.Threading名称空间的Mutex类(互斥类)进行线程同步。与Monitor锁一样,一次只有一个线程能获得一个给定的互斥。但Mutex要慢得多,但它增加了灵活性。例:
using System;using System.Threading;class Database {
Mutex mutex = new Mutex(false);//创建一个互斥,但不立即获得它
//注意:创建互斥在需要同步的方法之外,实际上它只要创建一个实例
public void SaveData(string text)//需要同步的方法
{
mutex.WaitOne();//等待获得互斥
...//需要同步的处理
mntex.Close();//释放互斥
} } Mutex类重载了三个构造函数:
Mutex()
//创建并使创建类立即获得互斥
Mutex(bool initiallyOwned)
//创建时可指定是否要立即获得互斥 Mutex(bool initiallyOwned, string muterName)//还可以指定互斥的名称 Mutex.WaitOne方法也重载了三次: Mutex.WaitOne()
//一直等待
Mutex.WaitOne(TimeSpan time, bool exitContext)//等待TimeSpan指定的时间 Mutex.WaitOne(int milliseconds, bool exitContext)//等待指定的毫秒 线程的用法:
1)并发操作:比如一个程序监视多个COM口,当每个COM接到信息时执行一段处理时。2)复杂长时间操作:一个长时间的复杂操作可能会使界面停滞,停止用户响应,如果还允许用户停止它,或者显示进度条、显示操作执行进程信息时。
反射(Reflection)就是能够在运行时查找类型信息,这是因为.NET编译的可执行(PE)文件中包括MSIL和元数据(metadata)。
反射的中心是类System.Type。System.Type是一个抽象类,代表公用类型系统(Common Type System, CTS)中的一种类型。
using System;using System.Reflection;//反射命名空间,必须引用 public static void Main(string[] args){
int i = 6;
Type t = i.GetType();
//根据实例得到类型
t = Type.GetType(“System.Int32”);//根据类型的字符名称得到类型
} 通过Assembly类可以得到已经编译.NET Framework程序的中所有类型,例: using System;using System.Diagnostics;//为了使用Process类 using System.Reflection;//为了使用Assembly类 class GetTypesApp {
protected static string GetAssemblyName(string[] args)
{
string assemblyName;
if(0 == args.Length)//如果参数为空,取当前进程的名称
{
Process p = Process.GetCurrentProcess();
assemblyName = p.ProcessName + “.exe”;
}
else
assemblyName = args[0];//取第一个参数,即当前运行程序名
return assemblyName;
}
public static void Main(string[] args)
{
string assemblyName = GetAssemblyName(args);
Assembly a = Assembly.LoadFrom(assemblyName);//调用编译程序集
Type[] types = a.GetTypes();
//得到多个类型
foreach(Type t in types)
//遍历类型数组
{
...//取得t.FullName,t.BaseType.FullName等类型信息
}
} } 一个应用程序可以包括多个代码模块。若要将一个cs文件编译一个模块,只要执行下面的命令:
csc /target:module 要编译的模块.cs //csc是C Sharp Compiler(C#编译器)然后在应用程序中using编译的模块.cs中的NameSpace即可应用了。要反射应用程序中所有代码模块(Module),只要:
Assembly a = Assembly.LoadFrom(assemblyName);//应用程序的物理文件名 Module[] modules = a.GetModules();foreach(Module m in modules){...//显示m.Name等
} 后期绑定(latebinding),例:
string[] fileNames = Directory.GetFiles(Environment.CurrentDirectory, “*.dll”);foreach(string fileName in fileNames){
Assembly a = Assembly.LoadFrom(fileName);
Type[] types = a.GetTypes();
foreach(Type t in types)
{
if(t.IsSubclassOf(typeof(CommProtocol)))//判断是否有CommProtocol的派生类
{
object o = Activator.CreateInstance(t);//生成实例
MethodInfo mi = t.GetMethod(“DisplayName”);
mi.Invoke(o, null);
//调用方法
}
} } //带参数的例子
namespace Programming_CSharp {
using System;
using System.Reflection;
public class Tester
{
public static void Main()
{
Type t = Type.GetType(“System.Math”);
Object o = Activator.CreateInstance(t);
// 定义参数类型
Type[] paramTypes = new Type[1];
paramTypes[0]= Type.GetType(“System.Double”);
MethodInfo CosineInfo = t.GetMethod(“Cos”, paramTypes);
//设置参数数据
Object[] parameters = new Object[1];
parameters[0] = 45;
//执行方法
Object returnVal = CosineInfo.Invoke(o, parameters);
Console.WriteLine(“The cosine of a 45 degree angle {0}”, returnVal);
}
} } 动态生成代码和动态调用的完整例子: //动态生成代码的部分 using System;using System.Reflection;using System.Reflection.Emit;//动态生成代码必须引用 namespace ILGenServer {
public class CodeGenerator
{
public CodeGenerator()
{
currentDomain = AppDomain.CurrentDomain;//得到当前域
assemblyName = new AssemblyName();//从域创建一个程序集
assemblyName.Name = “TempAssembly”;
//得到一个动态编译生成器,AssemblyBuilerAccess.Run表示只在内存中运行,不能保存
assemblyBuilder = currentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilerAccess.Run);
//从编译生成器得到一个模块生成器
moduleBuilder = assemblyBuilder.DefineDynamicModule(“TempModule”);
//模块生成器得到类生成器
typeBuilder = moduleBuilder.DefineType(“TempClass”, TypeAttributes.Public);
//为类添加一个方法
methodBuilder = typeBuilder.DefineMethod(“HelloWord”, MethodAttributes.Public, null, null);
//为方法写入代码,生成代码必须使用到IL生成器
msil = methodBuilder.GetILGenerator();
msil.EmitWriteLine(“Hello World”);msil.Emit(OpCodes.Ret);//最后还需要编译(build)一下类 t = typeBuilder.CreateType();
}
AppDomain currentDomain;
AssemblyName assemblyName;
AssemblyBuilder assemblyBuilder;
ModuleBuilder moduleBuilder;
TypeBuilder typeBuilder;
MethodBuilder methodBuilder;
ILGenerator msil;
object o;
Type t;
public Type T
{
get
{
return this.t;
}
}
} } //动态调用的部分
using System;using System.Reflection;using ILGenServer;//引用动态生成代码的类 public class ILGenClientApp {
public static void Main({
CodeGenerator gen = new CodeGenerator();//创建动态生成类
Type t = gen.T;
if(null!= t)
{
object o = Activator.CreateInstance(t);
MethodInfo helloWorld = t.GetMethod(“HelloWorld”);//为调用方法创建一个MethodInfo
if(null!= helloWorld)
{
helloWorld.Invoke(o, null);//调用方法
}
}
} } 调用DLL using System;using System.Runtime.InteropServices;//为了使用DLLImport特性
class PInvokeApp {
[DllImport(“user32.dll”, CharSet=CharSet.Ansi)] //CharSet.Ansi指定Ansi版本的函数(MessageBoxA),CharSet.Unicode指定Unicode版本的函数(MessageBoxW)
static extern int MessageBox(int hWnd, string msg, string caption, int type);//声明DLL中的函数
//[DllImport(“user32.dll”, EntryPoint=“MessageBoxA”)] //用这种方法使用不同的函数名
//static extern int MsgBox(int hWnd, string msg, string caption, int type);
//[DllImport(“user32.dll”, CharSet=CharSet.Unicode)] //调用Unicode版的DLL函数
//static extern int MessageBox(int hWnd, [MarshalAs(UnmanagedType.LPWStr)]string msg,// [MarshalAs(UnmanagedType.LPWStr)]string caption, int type);//将LPWStr翻译为string型,缺省情况系统只将LPStr翻译成string
public static void Main()
{
MessageBox(0, “Hello, World!”, “CaptionString”, 0);//调用DLL中的函数
} } 例2,使用回调: class CallbackApp {
[DllImport(“user32.dll”)]
static extern int GetWindowText(int hWnd, StringBuilder text, int count);
delegate bool CallbackDef(int hWnd, int lParam);
[DllImport(“user32.dll”)]
static extern int EnumWindows(CallbackDef callback, int lParam);
static bool PrintWindow(int hWnd, int lParam)
{
StringBuilder text = new StringBuilder(255);
GetWindowText(hWnd, text, 255);
Console.WriteLine(“Window Caption: {0}”, text);
return true;
}
static void Main()
{
CallbackDef callback = new CallbackDef(PrintWindow);
EnumWindows(callback, 0);
} } 关键字unsafe指定标记块在非控环境中运行。该关键字可以用于所有的方法,包括构造函数和属性,甚至还有方法中的代码块。关键字fixed负责受控对象的固定(pinning)。Pinning是一种动作,向垃圾收集(Garbage Collector, GC)指定一些不能被移动的对象。为了不在内存中产生碎片,.NET运行环境把对象四处移动,以便于最有效地利用内存。使用fixed后指定对象将不会被移动,所以就可以用指针来访问它。
C#中只能得到值类型、数组和字符串的指针。在数组的情况下,第一个元素必须是值类型,因为C#实际上是返回一个指向数组第一个元素的指针,而不是返回数组自身。& 取一个变量的内存地址(即指向该变量的指针)* 取指针所指变量的值-> 取成员
例:using System;class UnsafeApp {
public static unsafe void GetValues(int* x, int* y)
{
*x = 6;
*y = 42;
}
public static unsafe void Main()
{
int a = 1;
int b = 2;
GetValues(&a, &b);
} } fixed语法为:fixed(type* ptr = expression)statements其中type也可以为非控类型,也可是void;expression是任何产生一个type指针的表达式;statements是应用的代码块。例: fixed(int* f = &foo.x)//foo是Foo类的一个实例,x是Foo类的一个int属性 {
SetFooValue(f);//SetFooValue方法的定义为unsafe static void SetFooValue(int* x)} 传统的COM组件可以通过互操作层(COM Interop)与.NET运行环境交互。互操作层处理在托管运行环境和非托管区域中的COM组件操作之间传递所有的消息。
要使COM组件能在.NET环境中使用,必须为COM组件生成元数据。.NET运行环境用元数据层业判断类型信息。在运行时刻使用类型信息,以便生成RCW(Runtime Callable Wrapper,运行时可调用包装)。当.NET应用程序与COM对象交互时,RCW处理对COM对象的装载和调用。RCW还完成许多其他的工作,如管理对象标识、对象生存周期以及接口缓冲区。对象生存周期管理十分关键,因为.NET GC把对象到处移动,并且当对象不再使用时,自动处理这些对象。RCW服务告诉.NET,应用程序正与托管.NET组件交互,同时又使非托管COM组件“觉得”COM对象是被传统的COM客户端调用的。
为了为COM组件生成元数据包装,必须使用tlbimp.exe(TypeLib Importer)工具: tlbimp some_COM.tlb /out:som_COM.dll
第三篇:获取工作经验的八种方法
对于初次找工作或者准备跳槽的人来说,进入一个新的工作领域是件非常困难的事。你理想中的招聘广告是这样的:
“新成立公司招聘职员,要求对工作充满热情,高薪,高福利,无需工作经验,我们将提供培训”
然而现实通常是这样的:
“招聘某某部经理,1到2年工作经验,需要工作证明”
也许你逃避了大学实习,也许你从未找到过适合你的工作,也许你正经历一场中年事业危机,想要尝试一些新的东西,不管出于何种原因,你发现你自己没有也不可能获得相关工作经验。
幸运的是,在信息时代,那些“没有工作经验”的接口已经越来越没有市场了,通过各种各样的非传统途径来获取工作经验,即使你还没有得到梦想中的工作,你已经离它不远了。
义务工作:
登录或者之类的网站来寻找相关的工组机会,你会看到很多像“网上义工”之类的广告,它们对你的居住地没有任何要求。但因为这是没有薪水的,通过它们获取的经验(从时间和经验层面上)总是比同等的带薪工作要少。
●涉及领域:大部分工作,你可以为千里之外的慈善协会写文案,接送癌症病人接受治疗(心理咨询或者什么的)或者为当地公益组织拉赞助。
●优点:可以以此来建立人际关系网,增加工作经验,有利于将来找工作,还能增强你的自信心,同时这些工作对时间要求通常会很宽松。
自由职业工作网站:
在像, 和 网站上,你可以竞标到很多工作,从一天的短工到长期的专业工作应有尽有,假如你有什么特长,你应该去看看那里是否有你适合的工作。
因为这些网站采用客户反馈系统开评价你的工作,一开始你必须做些样品并且报酬要得低一些,一旦你得到了足够多的好评,那么你将通过你的努力挣很多钱。
●相关领域:程序设计,图式设计,市场营销,写作,销售,行政管理,等等 ●优点:培养独立工作能力,拓展人脉,获取大量工作经验,当然还有赚钱
●缺点:接到第一笔业务可能比较困难,而且在有些网站你必须付费成为会员后才能接业务。
考证
在某些领域,比别人多一张证会使你鹤立鸡群,如果你想打入一流的房地产公司,考一张房产经营证是值得的,在你还没有完成商科学业前,你可以用它来找份兼职,如果你是位运动或者营养品企业,你可以去考张私人教练证或者去你所在地的青年基督教会做义工。
●相关领域:心理咨询,运动健身,房地产,信息技术,财金保险,新世纪产业,保安,餐饮业,医疗等,去图书馆查查各个领域的资质证书和相关细节会对你有所帮助。
让你的爱好成为职业
如果你对你的职业生涯是非常认真的,那么好一个与你的爱好关系紧密的工作是再好不过的了,想想看你的爱好是什么,怎么让它成为你的工作。
你必须要有创造性,但当你在游戏中带领一群人战斗或者在虚拟世界中做买卖时,你正在学习很多有用的技能,我就在我简历的工作经验上写了这么一条:我在《无尽的任务》中的胜率是100%。
●相关领域:很明显,假如你梦想成为消防员,你不可能把放火灭火当成兴趣,所以这一条是有一定限制的,但是每个领域都有录像,书籍,图表,或者其他什么替代品来让你了解。
●优点:有趣
●缺点:也许没有人付你工资
当学徒
根据你喜欢的领域,你很可能会找到很多需要额外帮手的工作人员,你甚至可能根据你的工作时间为此安排一个宽松的时间表,你可以试着去问问看,被拒绝也没关系。
●相关领域:几乎所有,幸运的话你可以碰到个个体户或者自由职业者,你可能会去给医生接电话,为面包房洗盘子,为一个自由撰稿人校对稿子甚至帮魔术师打杂。
●优点:你可以交到在这个领域工作的朋友,获得相关的经验。
●缺点:没有报酬,而且有些人会想方设法瞒着你一些东西,因为他们害怕培养了未来的竞争对手。
传统自由撰稿人
即使写作不是你最大的职业理想,但这会是你迈向目标的好方法,一开始你可以向你目标领域的贸易出版物提供一些简单的东西,比如公司简介什么的,也许你需要提供一些未公布的样本来证明你有刺探情报的能力,但大多数贸易出版物愿意接受新人。
●相关领域:任何有其杂志的领域,像和这样的网站。
●优点:工作时间宽松,威望高后薪水相当可观。
●缺点:可能竞争非常激烈,取决于不同领域。
自己创业
想想看,时间并不会因为困难太多而等你,尽管你会面临合法性或者资格问题,但这些并不妨碍你开自己的公司。
●相关领域:尽管你不可能自己开一家整形诊所,但你可以从事广告,餐饮或者销售之类的行业,最好的选择是最资质要求和启动资金少的行业。
●优点:你自己当自己的老板,获取经验,还有可能赚很多钱,你甚至会爱上这个行业而放弃原先的理想。
●缺点:自己当老板后再去给别人打工时十分痛苦的,而且若你选择开资本密集型公司亏损的可能性是非常大的。
开网店
信不信由你,在易趣网买古旧纪念版T恤和旧货是很有意义的,尽管你把这当成兴趣,但在这过程中你会学到很多,你必须找到货源,考虑怎么做广告,拍照,应对客户或者做些网页设计什么的,你不必对这些事样样精通,但如果真那样的也值得你炫耀了。
●相关领域:市场营销(特别是网络营销),界面设计,摄影,客户服务,销售,网页设计(你可以在易趣网店里采用自定义风格),采购,以及可以想象的任何消费品。
●优点:时间宽松,可能非常有利可图
●缺点:在邮局排队,处理很多问题,一个人处理大小事务,除非你认识供货商不然你不会对行情很了解。
那么现在准备好提升你的经验值想着理想前进了吗?还有什么能阻止你呢?
第四篇:总结一下java获取路径几种途径
总结一下java获取路径几种途径--
在写java程序时不可避免要获取文件的路径...总结一下,遗漏的随时补上
1.可以在servlet的init方法里
String path = getServletContext().getRealPath(“/”);这将获取web项目的全路径
例如 :E:eclipseM9workspacetree tree是我web项目的根目录
2.你也可以随时在任意的class里调用
this.getClass().getClassLoader().getResource(“/”).getPath();这将获取 到classes目录的全路径
例如 : E:eclipseM9/workspace/tree/WEB-INF/classes/
这个方法也可以不在web环境里确定路径,比较好用
3.request.getContextPath();获得web根的上下文环境 如 /tree tree是我的web项目的root context
获取web项目的全路径
Java路径问题最终解决方案
—可定位所有资源的相对路径寻址
前言
Java的路径问题,非常难搞。最近的工作涉及到创建和读取文件的工作,这里我就给大家彻底得解决Java路径问题。
我编写了一个方法,比ClassLoader.getResource(String 相对路径)方法的能力更强。它可以接受“../”这样的参数,允许我们用相对路径来定位classpath外面的资源。这样,我们就可以使用相对于classpath的路径,定位所有位置的资源!
Java路径
Java中使用的路径,分为两种:绝对路径和相对路径。具体而言,又分为四种:
一、URI形式的绝对资源路径
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b URL是URI的特例。URL的前缀/协议,必须是Java认识的。URL可以打开资源,而URI则不行。URL和URI对象可以互相转换,使用各自的toURI(),toURL()方法即可!
二、本地系统的绝对路径
D:/java/eclipse32/workspace/jbpmtest3/bin/aaa.b Java.io包中的类,需要使用这种形式的参数。
但是,它们一般也提供了URI类型的参数,而URI类型的参数,接受的是URI样式的String。因此,通过URI转换,还是可以把URI样式的绝对路径用在java.io包中的类中。
三、相对于classpath的相对路径
如:相对于
file:/D:/java/eclipse32/workspace/jbpmtest3/bin/这个路径的相对路径。其中,bin是本项目的classpath。所有的Java源文件编译后的.class文件复制到这个目录中。
四、相对于当前用户目录的相对路径
就是相对于System.getProperty(“user.dir”)返回的路径。
对于一般项目,这是项目的根路径。对于JavaEE服务器,这可能是服务器的某个路径。这个并没有统一的规范!
所以,绝对不要使用“相对于当前用户目录的相对路径”。然而:
默认情况下,java.io 包中的类总是根据当前用户目录来分析相对路径名。此目录由系统属性 user.dir 指定,通常是 Java 虚拟机的调用目录。
这就是说,在使用java.io包中的类时,最好不要使用相对路径。否则,虽然在J2SE应用程序中可能还算正常,但是到了J2EE程序中,一定会出问题!而且这个路径,在不同的服务器中都是不同的!
相对路径最佳实践
推荐使用相对于当前classpath的相对路径
因此,我们在使用相对路径时,应当使用相对于当前classpath的相对路径。
ClassLoader类的getResource(String name),getResourceAsStream(String name)等方法,使用相对于当前项目的classpath的相对路径来查找资源。
读取属性文件常用到的ResourceBundle类的getBundle(String path)也是如此。
通过查看ClassLoader类及其相关类的源代码,我发现,它实际上还是使用了URI形式的绝对路径。通过得到当前classpath的URI形式的绝对路径,构建了相对路径的URI形式的绝对路径。(这个实际上是猜想,因为JDK内部调用了SUN的源代码,而这些代码不属于JDK,不是开源的。)
相对路径本质上还是绝对路径
因此,归根结底,Java本质上只能使用绝对路径来寻找资源。所有的相对路径寻找资源的方法,都不过是一些便利方法。不过是API在底层帮助我们构建了绝对路径,从而找到资源的!
得到classpath和当前类的绝对路径的一些方法
下面是一些得到classpath和当前类的绝对路径的一些方法。你可能需要使用其中的一些方法来得到你需要的资源的绝对路径。
1,FileTest.class.getResource(“")
得到的是当前类FileTest.class文件的URI目录。不包括自己!如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/com/test/ 2,FileTest.class.getResource(”/“)
得到的是当前的classpath的绝对URI路径。
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
3,Thread.currentThread().getContextClassLoader().getResource(”“)
得到的也是当前ClassPath的绝对URI路径。
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
4,FileTest.class.getClassLoader().getResource(”“)
得到的也是当前ClassPath的绝对URI路径。
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/ 5,ClassLoader.getSystemResource(”“)
得到的也是当前ClassPath的绝对URI路径。
如:file:/D:/java/eclipse32/workspace/jbpmtest3/bin/
我推荐使用Thread.currentThread().getContextClassLoader().getResource(”“)来得到当前的classpath的绝对路径的URI表示法。
Web应用程序中资源的寻址
上文中说过,当前用户目录,即相对于System.getProperty(”user.dir“)返回的路径。
对于JavaEE服务器,这可能是服务器的某个路径,这个并没有统一的规范!而不是我们发布的Web应用程序的根目录!
这样,在Web应用程序中,我们绝对不能使用相对于当前用户目录的相对路径。
在Web应用程序中,我们一般通过ServletContext.getRealPath(”/“)方法得到Web应用程序的根目录的绝对路径。这样,我们只需要提供相对于Web应用程序根目录的路径,就可以构建出定位资源的绝对路径。这是我们开发Web应用程序时一般所采取的策略。
通用的相对路径解决办法容易的解决相对路径问题。
Java中各种相对路径非常多,不容易使用,非常容易出错。因此,我编写了一个便利方法,帮助更Web应用程序中使用JavaSE运行的资源寻址问题
在JavaSE程序中,我们一般使用classpath来作为存放资源的目的地。但是,在Web应用程序中,我们一般使用classpath外面的WEB-INF及其子目录作为资源文件的存放地。
在Web应用程序中,我们一般通过ServletContext.getRealPath(”/“)方法得到Web应用程序的根目录的绝对路径。这样,我们只需要提供相对于Web应用程序根目录的路径,就可以构建出定位资源的绝对路径。
Web应用程序,可以作为Web应用程序进行发布和运行。但是,我们也常常会以JavaSE的方式来运行Web应用程序的某个类的main方法。或者,使用JUnit测试。这都需要使用JavaSE的方式来运行。
这样,我们就无法使用ServletContext.getRealPath(”/“)方法得到Web应用程序的根目录的绝对路径。而JDK提供的ClassLoader类,它的getResource(String name),getResourceAsStream(String name)等方法,使用相对于当前项目的classpath的相对路径来查找资源。
读取属性文件常用到的ResourceBundle类的getBundle(String path)也是如此。
它们都只能使用相对路径来读取classpath下的资源,无法定位到classpath外面的资源。
Classpath外配置文件读取问题
如,我们使用测试驱动开发的方法,开发Spring、Hibernate、iBatis等使用配置文件的Web应用程序,就会遇到问题。
尽管Spring自己提供了FileSystem(也就是相对于user,dir目录)来读取Web配置文件的方法,但是终究不是很方便。而且与Web程序中的代码使用方式不一致!
至于Hibernate,iBatis就更麻烦了!只有把配置文件移到classpath下,否则根本不可能使用测试驱动开发!
这怎么办?
通用的相对路径解决办法”)方法来定位资源。
面对这个问题,我决定编写一个助手类ClassLoaderUtil,提供一个便利方法[public static URL getExtendResource(String relativePath)]。在Web应用程序等一切Java程序中,需要定位classpath外的资源时,都使用这个助手类的便利方法,而不使用Web应用程序特有的ServletContext.getRealPath(“/利用classpath的绝对路径,定位所有资源 这个便利方法的实现原理,就是“利用classpath的绝对路径,定位所有资源”。
ClassLoader类的getResource(”“)方法能够得到当前classpath的绝对路径,这是所有Java程序都拥有的能力,具有最大的适应性!
而目前的JDK提供的ClassLoader类的getResource(String 相对路径)方法,只能接受一般的相对路径。这样,使用ClassLoader类的getResource(String 相对路径)方法就只能定位到classpath下的资源。
如果,它能够接受“../”这样的参数,允许我们用相对路径来定位classpath外面的资源,那么我们就可以定位位置的资源!
当然,我无法修改ClassLoader类的这个方法,于是,我编写了一个助手类ClassLoaderUtil类,提供了[public static URL getExtendResource(String relativePath)]这个方法。它能够接受带有“../”符号的相对路径,实现了自由寻找资源的功能。
通过相对classpath路径实现自由寻找资源的助手类的源代码:
import java.io.IOException;import java.io.InputStream;
import java.net.MalformedURLException;import java.net.URL;import java.util.Properties;
import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;
/**
*@author沈东良shendl_s@hotmail.com
*Nov29,2006 10:34:34AM
*用来加载类,classpath下的资源文件,属性文件等。
*getExtendResource(StringrelativePath)方法,可以使用../符号来加载classpath外部的资源。
*/
publicclass ClassLoaderUtil {
privatestatic Log log=LogFactory.getLog(ClassLoaderUtil.class);
/**
*Thread.currentThread().getContextClassLoader().getResource(”“)
*/
/**
*加载Java类。使用全限定类名
*@paramclassName
*@return
*/
publicstatic Class loadClass(String className){
try {
return getClassLoader().loadClass(className);
} catch(ClassNotFoundException e){
thrownew RuntimeException(”class not found '“+className+”'“, e);
}
}
/**
*得到类加载器
*@return
*/
publicstatic ClassLoader getClassLoader(){
return ClassLoaderUtil.class.getClassLoader();
}
/**
*提供相对于classpath的资源路径,返回文件的输入流
*@paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使用../来查找
*@return 文件输入流
*@throwsIOException
*@throwsMalformedURLException
*/
publicstatic InputStream getStream(String relativePath)throws MalformedURLException, IOException {
if(!relativePath.contains(”../“)){
return getClassLoader().getResourceAsStream(relativePath);
}else{
return ClassLoaderUtil.getStreamByExtendResource(relativePath);
}
}
/**
*
*@paramurl
*@return
*@throwsIOException
*/
publicstatic InputStream getStream(URL url)throws IOException{
if(url!=null){
return url.openStream();
}else{
returnnull;
}
}
/**
*
*@paramrelativePath必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使用../来查找
*@return
*@throwsMalformedURLException
*@throwsIOException
*/
publicstatic InputStream getStreamByExtendResource(String relativePath)throws MalformedURLException, IOException{
return ClassLoaderUtil.getStream(ClassLoaderUtil.getExtendResource(relativePath));
}
/**
*提供相对于classpath的资源路径,返回属性对象,它是一个散列表
*@paramresource
*@return
*/
publicstatic Properties getProperties(String resource){
Properties properties = new Properties();
try {
properties.load(getStream(resource));
} catch(IOException e){
thrownew RuntimeException(”couldn't load properties file '“+resource+”'“, e);
}
return properties;
}
/**
*得到本Class所在的ClassLoader的Classpat的绝对路径。
*URL形式的 *@return
*/
publicstatic String getAbsolutePathOfClassLoaderClassPath(){
ClassLoaderUtil.log.info(ClassLoaderUtil.getClassLoader().getResource(”“).toString());
return ClassLoaderUtil.getClassLoader().getResource(”“).toString();
}
/**
*
*@paramrelativePath 必须传递资源的相对路径。是相对于classpath的路径。如果需要查找classpath外部的资源,需要使用../来查找
*@return资源的绝对URL
*@throwsMalformedURLException
*/
publicstatic URL getExtendResource(String relativePath)throws MalformedURLException{
ClassLoaderUtil.log.info(”传入的相对路径:“+relativePath);
//ClassLoaderUtil.log.info(Integer.valueOf(relativePath.indexOf(”../“)));
if(!relativePath.contains(”../“)){
return ClassLoaderUtil.getResource(relativePath);
}
String classPathAbsolutePath=ClassLoaderUtil.getAbsolutePathOfClassLoaderClassPath();
if(relativePath.substring(0, 1).equals(”/“)){
relativePath=relativePath.substring(1);
}
ClassLoaderUtil.log.info(Integer.valueOf(relativePath.lastIndexOf(”../“)));
String wildcardString=relativePath.substring(0,relativePath.lastIndexOf(”../“)+3);
relativePath=relativePath.substring(relativePath.lastIndexOf(”../“)+3);
int containSum=ClassLoaderUtil.containSum(wildcardString, ”../“);
classPathAbsolutePath= ClassLoaderUtil.cutLastString(classPathAbsolutePath, ”/“, containSum);
String resourceAbsolutePath=classPathAbsolutePath+relativePath;
ClassLoaderUtil.log.info(”绝对路径:“+resourceAbsolutePath);
URL resourceAbsoluteURL=new URL(resourceAbsolutePath);
return resourceAbsoluteURL;
}
/**
*
*@paramsource
*@paramdest
*@return
*/
privatestaticint containSum(String source,String dest){
int containSum=0;
int destLength=dest.length();
while(source.contains(dest)){
containSum=containSum+1;
source=source.substring(destLength);
}
return containSum;
}
/**
*
*@paramsource
*@paramdest
*@paramnum
*@return
*/
privatestatic String cutLastString(String source,String dest,int num){
// String cutSource=null;
for(int i=0;i
source=source.substring(0, source.lastIndexOf(dest, source.length()-2)+1);
}
return source;
}
/**
*
*@paramresource
*@return
*/
publicstatic URL getResource(String resource){
ClassLoaderUtil.log.info(”传入的相对于classpath的路径:“+resource);
return ClassLoaderUtil.getClassLoader().getResource(resource);
}
/**
*@paramargs
*@throwsMalformedURLException
*/
publicstaticvoid main(String[] args)throws MalformedURLException {
//ClassLoaderUtil.getExtendResource(”../spring/dao.xml“);
//ClassLoaderUtil.getExtendResource(”../../../src/log4j.properties“);
ClassLoaderUtil.getExtendResource(”log4j.properties“);
System.out.println(ClassLoaderUtil.getClassLoader().getResource(”log4j.properties").toString());
}
}
第五篇:C#实习总结
现在的社会日新月异,科技飞速发展,但是随之而来的环境问题也日益严重,当然这也有很多其他诸如人口、能源等因素,不过这些让人们越来越重视绿色产业,而软件就是首当其冲的一个。我积极参加了学校组织的软件实习,主要是对.Net方面的实训和实战,一方面想要继续深造之前在大学里面学习的软件方面的知识,另一方面,也是为了自己的职业规划,说直接点,就是以后找份好工作。虽然实训中时间安排有点紧,但很充实,学到了很多之前在大学课堂上没有学到的知识,可以说我从这次实训中的收获很大。
对于计算机编程,我可以说从高中就开始接触,大学从专科开始一直学习的都是软件开发的专业,学过C#、Java,学过开发,也学过测试。但是这次实训让我体会了和之前完全不同的学习感受,不仅是时间安排、或者说效率还是教学授课的方式上,都是和大学课堂完全不同的,不是一节课讲一点,也不是一点一点教给你,这个实训中更多的是培养我们独立动手解决实际问题的能力,分析考虑问题的方法思路,让我们真正成长起来。
学校为我们提供了良好的学习的平台,提供了好工作的面试机会。我们觉得我们更应该充分利用资源,珍惜机会,努力学习,不断地给自己“充电”,这样才能不断的开拓进取,勇于创新,才不至于被社会淘汰。
这次实习中,我们主要有S0、S1、S2三个阶段,S0阶段主要是自学C#基础知识,S1阶段是在老师的指导下学习C#基础编程、C#桌面应用开发、C#数据库应用开发、C#网络应用开发、软件测试和软件工程几个方面的技术方面的课程,S2阶段则是进入项目实战,做实际项目来进行巩固和总结。整个过程中,还有穿插了职业素养课和英语口语课,学技术的同时,我们也注重职业素养的培养和英语口语的锻炼。
到目前为止,我们实习的主要成果有(按时间顺序):Point24(24点游戏求解小程序)、HandsUp(举手游戏模拟小程序)、SimpleCalculator(简单计算器)、GottaU(捕捉鼠标小游戏)、TypeGame(打字小游戏)、WebBrowser(简易网络浏览器)、Checker(单机对战跳棋小游戏)、MDITextEditor(多文档界面文本编辑器)、FileManager(文件管理器)、SimpleMediaPlayer(简单媒体播放器)等,这些小程序或是项目,虽然和市面的那些软件比起来,在功能强大、界面美观、Bug稀少等方面都有欠缺,但是都是实打实的,我们自己动脑、动手做出来的,当然在做的过程中遇到了不少困难、挫折,但是正因为这些困难和挫折,我们才真正学到了知识和技术。更值得注意的则是,在老师带领我们做项目的过程中,我们从老师的言传身教中学到了很多很多编程思想、解决问题的方法思路等各种“无形”的知识。
众多收获之中,让我感触颇深的,则是老师给我们介绍的“10-90”原则和“Quality-Client-Cost”原则。“10-90”原则的意思是,我们通常都是花10%的代价就可以完成一件事或者一个项目的90%,而剩下的10%,却需要我们花费90%的金钱、精力等各种代价,能不能做到这最后的10%,往往是衡量一个人或者一家公司很重要的一个原则。而且这个原则还是可以嵌套的,最后10%的部分中,也可以再分成90%和10%,同样是开始的90%需要10%的代价,最后的10%需要90%的代价。这个原则不仅适用于做软件、做项目、做公司,其实人生中做人也是如此,很多时候最后的10%是很重要的一把标尺。虽然不能说这个原则放之四海而皆准,但是确实是适用于很多地方、很多方面,让我获益良多。“Quality-Client-Cost”原则讲的则是做软件或是做软件公司的一个原则,就是质量一定要放在第一位,客户在第二位。我自己原本心目中对这三项的排序是Client-Quality-Cost”,但是老师的讲解点醒了我,最具有说服力的例子,就是像微软这样的大公司,都是Quality第一的,他们宁可花费多一些,价格贵一些,但是一定把产品尽善尽美。这个原则同样可以用在人生中,Quality就是人品、品德、素质,Client是朋友、客户、亲人,我们当然应该把个人的品格放在第一位。这些都属于这次实习中,我在技术以外的收获。
另外在实习还有职业素养课中,也学到了很多其他在今后的工作中,要注意的东西,首先要有团队合作精神,现金的大中型软件的编写,分工越来越细,这样在开发、测试的过程中,团队的合作、成员间的交流就变得尤为重要,是决定效率的重要因素;要学会独立解决问题,工作不比在学校学习,遇到的各种实际问题不会有老师专门帮助解决,自己独立分析、解决问题的能力就变得极其重要;要有创新精神,在工作和学习中,如果只是一味的模仿、学习,那就永远不会真正得学得得心应手、融会贯通,必须自己去实践,在实践中创新,这样才能把学来的,变成自己的;要有耐心,学会自我规划和管控,耐心自是不必多说,有耐心才能把事情仔细做好,而公司的管理制度和学校根本上的不同,使得自我规划和管控就成了能否按时圆满完成任务的很重要的条件。
通过这次实习,我在个人素质方面有较大的提高,不仅是在C#的技术方面,还包括面对、分析和处理问题的思路、能力,思维的创造性和全面性,交流和沟通能力,英语口语水平,同时也克服了一些自己的缺点,获得很大进步。
总的来说,这次实习对我有很大意义,不仅巩固和实践了之前在大学课堂上学到的各种知识,扩充了自己对软件技术方面的知识储备,同时也给了我很大的成就感,增强了我的自信。并不是说因为我做成的很难的程序,或者做出来的软件很强很完善,但都是自己认真完成的,过程中有遇到各种困难和挫折,但是经
过网上查资料、小组讨论、向老师请教等几种途径,最终都克服了,当最终自己完成时,总会有一些成就感。
此外,我还人知到在以后的工作和学习中,不仅要努力学习和锻炼专业技能知识,包括C#技术、算法技巧、MVC模式框架的开发、中间技术等等,而且也要注意让自己兴趣广泛起来,拓宽自己的知识面,多积累各种知识,这不仅对以后的软件开发工作有一定好处,对自身的个人修养的提升也是大有裨益。
社会的竞争是激烈的,我想我们应该好好把握住大学学习的时间,充实、完善自我,掌握更多的专业知识,加强实践和设计能力,同时也注意全面发展,这样更有利于将来的发展,在自己的专业领域有所作为。