.Net培训个人总结笔记6

学习交流,欢迎转载。转载请注明文章来源:http://www.cnblogs.com/lgjspace/archive/2011/10/12/2211054.html

经验:
代码的编写和调试时尽量少用Try Catch,在产品完成之后发布之前,为了防止一些有可能出现始料不及情况的代码段出现错误,才在该代码段处加上Try Catch。因为这样会有可能在程序完成前的开发或测试时期就把自己程序中的bug被掩埋起来了,这会给程序带来更多潜在的危险。但也有在开发测试时就用TryCatch的情况,例如写Socket时可以通过TryCatch来监测连接是否已经断开,但这种(开发时就用TryCatch的)情况一般比较少见。

 

原理:
对文件系统操作的本质是通过数据流来实现的。
所谓的流,通俗来说就是把所有需要传输的(图像、音视频、文本、文件等)信息转换成字节类型的数组(Byte[])

 

流与文件的区别:
一般来说,流的存放时间比较短暂,而且一般是基于内存的;而文件的存放时间比较长,数据是放在硬盘上的。

 

拓展:
凡是跟流有关的所有类,其都是继承自 System.IO 命名空间下的 Stream 类的,Stream 类是所有流相关的类的基类。Stream 是抽象类,只能被继承,不能被实例化。

 

细节:
流的读(Read)和写(Write)的介绍:
简单来讲就是:“发送端”→写入(Write)→“流”(Stream)→读出(Read)→“接收端”。类比成这样一个模型:数据发送端、流(Stream)、数据接收端,数据发送端通过流的 Write 方法写入流,然后数据接收端通过流中的 Read 方法从流中读出已经从发送端写入到流中的数据,从而实现数据的传输。

 

重点:
Stream 类中 Write 方法的参数解释(Read方法也一样):
1.buffer(byte[]类型),即要写入到流中(或从流中读出来)的内容数据(以字节数组形式赋值给该参数);
2.offset(int类型)偏移量,表示是要从第几个字节开始传(从 0 开始算);
3.count(int类型)字节数,表示要传递多少个字节。
类似地,Stream 有 WriteByte 和 ReadByte 方法,顾名思义,每次只读取或只写入一个字节,传入的参数更加简单,就是需要写入的字节内容(ReadByte方法甚至不需要传入任何参数)。

 

经验:
1.在.Net框架中凡是有“Begin”为前缀的方法肯定都是异步方法。一般是结合多线程来使用。
2.所有的流在使用完毕后一定要调用 Close() 方法来把流关闭!!!否则,被这个流操作着的资源或文件就一直被占用,文件就不能被外界操作。在流(Stream)中,一般 Close() 方法中会在内部调用 Dispose() 方法来销毁资源。

 

技巧:
Obsolete(已过时),在MSDN上凡是出现了该标识的类、成员、属性、方法等,即表明该类已经过时,有更好的类似功能的东西可以把这些类或者成员等代替,但这些类或者成员等仍然可以使用,可用性不会受影响。

 

细节:
Stream 中的 超时机制(Timeout)是一种容错机制。

 

细节:
流(Stream )中的 Length 属性(长度)表示的是当前的流的内存数组的长度;Position 属性则是表示当前指针的位置。

 

 技巧:
若想查看.Net框架里的某个类(例如 Stream 类)的结构,可以在项目中随便新建一个类(假设类名为Class1),然后把 Class1 继承自 Stream(即写成“class Class1:Stream”),然后用类视图打开类 Class1 ,右键 Class1 的图框,在右键菜单中选中“显示基类”(Show Basic),即可看到 Class1 继承的 Stream 类的结构了。

 

小常识:
凡是在类视图中用斜体显示的类、方法、属性字段等,都表示是没被实现的,

 

介绍:
RichTextBox:富文本编辑器

 

细节:
文件的后缀名是给人看的,程序和操作系统不是通过后缀名来识别文件的,而是通过文件的文件头来识别文件类型的。

 

经验:
在流的读操作中,一般情况下当流读到最后一个位置时,StreamReader 类的对象的 Peek()方法返回-1。

Peek()方法的官方介绍:
Peek 方法返回一个整数值,以确定是到达文件结尾还是发生另一个错误。这允许用户首次检查返回值在强制转换为 Char 类型前是否为 -1。
此操作未更改 TextReader 的当前位置。如果没有更多字符可用,则返回的值为 –1。默认实现将返回 -1。

 

细节:
流相关的资源也可以通过使用using(){} 的方式来让程序自动回收。

 

经验:
MSDN中:带黄色字母 S 标记的是静态的类或成员。

 

重点:
在某些情况下,资源的手动回收也是必须的。如下面的代码:

 1 namespace tmp
2 {
3 public partial class Form1 : Form
4 {
5 public Form1()
6 {
7 InitializeComponent();
8 }
9
10 private string sourceFileName, targetFileName;
11 private void btnSourceFile_Click(object sender, EventArgs e)
12 {
13 OpenFileDialog ofd = new OpenFileDialog();
14 if (DialogResult.OK != ofd.ShowDialog())
15 {
16 return;
17 }
18 string fileName = ofd.FileName;
19 sourceFileName = fileName;
20 txtSourcePath.Text = fileName;
21 }
22
23 private void btnTargetFile_Click(object sender, EventArgs e)
24 {
25 SaveFileDialog sfd = new SaveFileDialog();
26 if (DialogResult.OK != sfd.ShowDialog())
27 {
28 return;
29 }
30 string fileName = sfd.FileName;
31 targetFileName = fileName;
32 txtTargetPath.Text = fileName;
33 }
34
35 byte[] buffer; //这是用来在文件拷贝时作为缓冲区用的字节数组,问题就是在于这数组上。
36 private void btnStartCopy_Click(object sender, EventArgs e)
37 {
38 if (true == string.IsNullOrEmpty(sourceFileName) || true == string.IsNullOrEmpty(targetFileName) || true == string.IsNullOrWhiteSpace(sourceFileName) || true == string.IsNullOrWhiteSpace(targetFileName))
39 {
40 MessageBox.Show("路径非法!");
41 return;
42 }
43 FileStream fsRead = new FileStream(sourceFileName, FileMode.Open);
44 buffer = new byte[fsRead.Length];
45 fsRead.Read(buffer, 0, (int)fsRead.Length);
46 fsRead.Close();
47 MessageBox.Show("读入成功!");
48
49 FileStream fsWrite = new FileStream(targetFileName, FileMode.Create);
50 fsWrite.Write(buffer, 0, buffer.Length);
51 fsWrite.Close(); //此时复制已经成功,但字节数组 buffer 由于是类 tmp 的字段(这类似于C/C++中的全局变量),正常的生命周期还没有到达结束,所以占用的资源还没有被释放掉,以至于“文件拷贝完了,但数据还残留在内存上”,造成内存的长期占用。
52 MessageBox.Show("复制成功!");
53 }
54 }
55 }

如代码中的注释所说,当流操作完成之后,字节数组 buffer 由于是类 tmp 的字段(这类似于C/C++中的全局变量),正常的生命周期还没有到达结束,所以占用的资源还没有被释放掉,以至于“文件拷贝完了,但数据还残留在内存上”,造成内存的长期占用。因此,应该在拷贝操作完成后,程序结束前要手动控制GC回收资源,方法很简单,在需要.Net进行回收的时候首先执行一下“buffer = null”,让 buffer 变量“扔掉”它自己里面的数据(这一步是必须的,不可以跳过),然后显式调用一下垃圾回收器的 Collect() 方法,即显式执行“GC.Collect();”,这样即可命令程序立刻执行清理操作,以实现资源回收的效果。之所以在执行 Collect() 方法之前要把所需清除的变量“=null”,是因为 buffer 是类的字段,生命周期还没结束,所以里面的数据还不算是“垃圾”,所以垃圾回收器当然就“不敢动”这些数据了,而要是 buffer=null 之后,里面的数据就成了“没娘的孩子”了,成了真正的“垃圾”,所以资源就能被回收,占用的空间就能够被释放了。

 

经验:
当使用了本地资源、文件资源、或者流资源后,建议手动把资源和相关的变量“解绑”,然后显式地调用“GC.Collect()”方法来回收资源。

 

细节:
在C#中变量名本身是值类型,是放在栈里面的,而无论变量的类型是引用类型还是值类型。例如“byte[] buffer = new byte[10];”这句中,数组明显是引用类型的,放在托管堆中,但数组变量的变量名 buffer 本身则是值类型的,本身被放在栈里面,而这名字相当于 C/C++ 中的指针,这“指针”指向的是托管堆中存放该变量名对应的字节数组的内存的地址。

 

引述:
引述自MSDN官方的说法:
File 类:提供用于创建、复制、移动和打开文件的静态方法,并协助创建 FileStream 对象。

 

细节:
Path(路径)和目录(Directory)的区别:
路径相当于文件地址(如“D:\软件(10.10.28)\360ARP防火墙3.0\setupbeta_7.3.0.1008o.exe”等);
目录相当于文件夹地址(如“D:\软件(10.10.28)\360ARP防火墙3.0\”等)。

 

细节:
1.FileInfo、DirectoryInfo 和 File、Directory 基本是一样的,唯一区别只是前两个不像后两个那样是静态的、后两个需要实例化后才能使用。
2.DriveInfo 类是对驱动器操作相关的类。

 

细节:
在.Net下,WinForm 和 WebForm 的控件的默认命名规范是不一样的,前者默认是Camel形式(即第一个单词开头字母小写,第二个之后的所有单词开头字母大写),而后者则默认是Pascal(即每个单词开头字母都是大写,而无论单词是不是第一个)。

posted @ 2011-10-12 23:03  梁国锦  阅读(213)  评论(0编辑  收藏  举报