第7章 C#中的文件,数组和异常

时间:2022-09-03 13:46:03

 第7章 C#中的文件,数组和异常

C#处理数组和文件相当容易,并引入异常来简化错误处理。


7.1 数组

const int MAX=10;
float[] xy=new float[MAX];
for (int i=0;i<MAX;i++){
 xy[i]=i;
}
应当习惯数组的循环是从零到数组边界值减1,正如我们在前面的代码中所做的那样。
所有的数组变量都有一个长度属性,可以根据它查出数组的大小。
float[] z=new float[20];
for (int j=0;j<=z.length;j++){
 z[j]=j;
}
C#中的数组是动态的,可以在任何时候重新分配空间。
在类内部创建一个数组的引用,然后分配空间,可这样写:
float[] z;  //declare here
z=new float[20]; //create later


7.2 集合对象

7.2.1 ArrayList

ArrayList(数组表)对象本质上是一个可变长的数组,可以根据需要添加元素
使用ArrayList的方法可以向数组中添加元素,或取出,修改某个元素.
float[] z={1.0f,2.9f,5.6f};
ArrayList arl=new ArrayList();
for (int j=0;j<z.length;j++){
 arl.Add(z[j]);
}
ArrayList有一个Count属性,可用于确定它所包含的元素数目.
for (j=0;j<arl.count;j++){
 Console.WriteLine(arl[j]);
}
foreach(float a in arl){
 Console.WriteLine(a);
}

ArrayList的方法列表:
Clear
删除ArrayList的内容

Contains(object)
如果ArrayList包含该对象,则返回true

CopyTo(array)
将ArrayList全部内容拷贝到一个一维数组中

IndexOf(object)
返回该对象的第一个索引值

Insert(index,object)
将元素插入到指定的位置

Remove(object)
从表中删除该元素

RemoveAt(index)
删除指定对象的元素

Sort
对ArrayList排序


从ArrayList中取出的每个对象都是object类型,这就意味着,在使用前通常需要将其转换成合适的类型.
float x=(float)arl[j];


7.2.2 Hashtable 哈希表

Hashtable是一个可变长数组,表中的每个项目都通过关键字值来访问.
关键字一般是某个字符串,也可以是其他类型的对象.
使用Hashtable可以快速访问一个大而无序的记录表
还可以将关键字和项目值颠倒过来,创建一个每条项目都是唯一的表.

Hashtable hash=new Hashtable();
float freddy=12.3f;
hash.Add("fred",freddy); //add to table
//get this one back out
float temp=(float)hash["fred"];

注意,同ArrayList一样.从Hashtable中得到的数据也必须转换成合适的类型
Hashtable也有一个Count属性,可用来获取关键字的列表或项目的列表.


7.2.3 SortedList

SortedList(排序表)类保存了两个内部数组,可以通过基于零的下标或字母关键字来获取元素.
float sammy=44.55f;
SortedList slist=new SortedLIst();
slist.Add("fred",freddy);
slist.Add("sam",sammy);

//get by index
float newFred=(float)slist.GetByIndex(0);

//get by key
float newSam=(float)slist["sam"];

在System.Collections名字空间还可以看到Stack(堆栈)对象和Queue(队列)对象,
他们的特性和读者期望一样,可以在系统帮助文档中找到他们的方法.


7.3 异常

C#用异常完成错误处理,而不是采用其他难以使用的错误检测方法。
异常处理就是把引起错误的语句包含在try块中,然后用catch语句捕获错误.
try{
 //Statements
}
catch(Exception e){
 //do these if an error occurs
finally{
 //do these anyway
}
一般使用这种方法检查文件处理语句的错误,
也可以用语捕获数组下标越界和许多其他错误情形。
执行try块中的语句若无错误,则转到finally语句;
若有错误,则转到catch语句,然后转到finally语句.
try{
 //note-one too many
 for(int i=0;i<=arl.count(arl[i]);
}
catch(Exception e){
 Console.WriteLine(e.Message);
}
这段程序输出了错误信息和程序中的调用位置,然后继续运行.
相反,若不捕获异常,运行时会给出一条错误信息.
程序将退出运行不再继续下去并给出出错界面.

C#中的常用异常类

AccessException
访问类的方法或数据时出错

ArgumentException
传给方法的参数是无效的

ArgumentNullException
参数是空的

ArithmeticException
上溢或下溢

DivideByZereException
被0除

IndexOutOfRangeException
文件没找到

EndOfStreamException
访问超出了输入数据流(如文件)的末端

DirectoryNotFoundException
目录没找到

NullReferenceException
对象变量没有初始化成一个实际的值


7.4 多个异常

也可以在一系列catch块中捕获多个异常并分别进行处理:
try{
 for(int i=0;i<=arl.count;i++){
  int k=(int)(float)arl[i];
  Console.Write(i+""+k/i);
 }
}
catch(DivideByZereException e){
 printZero(e);
}
catch(IndexOutofRangeException e){
 printOErr(e);
}
catch(Exception e){
 printErr(e);
}
这样做可以让程序以不同方式从各种错误中恢复过来.


7.5 抛出异常

try{
 //statements
}
catch(Exception e){
 throw(e); //pass on to calling program
}

7.6 文件处理

C#中的文件处理对象提供了一些相当灵活的处理文件的方法.

7.6.1 File对象

File(文件)对象代表一个文件,并为检测文件是否存在,文件更名和文件删除提供了一些有用的方法。
所有这些方法都是静态的,也就是说,
不能使用new运算符创建file的实例,但可以直接使用File的方法.

if(File.Exists("Foo.txt"))
 File.Delete("foo.txt");

用File对象获得用于读写文件数据的文件流(FileStream)

//open text file for reading
StreamReader ts=File.OpenText("foo1.txt");

//open any type of file for reading
FileStream fs=File.OpenRead("foo2.any");

一些比较有用的File方法:

File.FileExists(filename)
若文件存在,则为true

File.Delete(filename)
删除该文件

File.AppendText(String)
添加文本

File.Copy(fromFile,toFile)
拷贝一个文件

File.Move(fromFile,toFile)
移动文件,删除旧文件

File.GetExtension(filename)
返回文件的扩展名

File.HasExtension(filename)
若文件有扩展名,则为true


7.6.2 读文本文件

StreamReader ts=File.OpenText("foo1.txt");
string s=ts.ReadLine();

7.6.3 写文本文件

//open for writing
StreamWriter sw=File.CreateText("foo3.txt");
sw.WriteLine("Hello file");

7.6.3 写文本文件

//append to text file
StreamWriter asw=new StreamWriter("foo1.txt",true);
//true为用于追加的布尔参数

7.7 文件处理中的异常

try{
 //open text file for reading
 StreamReader ts=File.OpenText("foo1.txt");
 string s=ts.ReadLine();
}
catch(Exception e){
 Console.WriteLine(e.Message);
}

7.8 检测文件末尾

private StreamReader rf;
private bool eof;
public String readLine(){
 String s=rf.ReadLine();
 if(s==null)
  eof=true;
 return s;
}
public bool fEof(){ //文件读入类中创建一个文件结束函数
 return eof;
}

另外一种保证读数据不会超过文件末尾的方法:
Peek方法返回文件中下一个字符的Ascii码,如果没有字符则返回-1.
public String read_Line(){
 String s="";
 if(rf.Peek()>0){
  s=rf.ReadLine();
 }
 else{
  eof = true;
 }
 return s;
}

7.9 csFile类

将文件方法包装在一个带有易用方法的简单类中会更方便,于是我们编写了csFile类
这里把文件名fileName和路径包含在构造函数里,也可以用重载的OpenForRead和OpenForWrite语句把它传递进来.
public class csFile{
 private string fileName;
 StreamReader ts;
 StreamWriter ws;
 private bool opened,writeOpened;
 public csFile(){
  init();
 }
 private void init(){
  opened=false;
  writeOpened=false;
 }
 public csFile(string file_name){
  fileName=file_name;
  init();
 }
 //打开用于读数据的文件
 public bool OpenForRead(string file_name){
  fileName=file_name;
  try{
   ts=new StreamReader(fileName);
   opened=true;
  }
  catch(FileNotFoundException e){
   return false;
  }
  return true;
 } 
 //接下来,可以用readLine方法从文本文件读数据
 public string readLine(){
  return ts.ReadLine();
 }
 //打开一个用于写数据的文件,并向其中写入若干文本:
 public void writeLine(string s){
  ws.WriteLine(s);
 }
 public bool OpenForWrite(string file_name){
  try{
   ws=new StreamWriter(file_name);
   fileName=file_name;
   writeOpened=true;
   return true;
  }
  catch(FileNotFoundException e){
   return false;
  }
 }
}
在任何需要读写文件时,都会使用这个简化的文件方法包装类.