java常用类解析二

来源:互联网 发布:贵州广电网络通讯录 编辑:程序博客网 时间:2024/05/16 11:22

IO系统File类及文件搜索工具类

1、先看一个File类的简单的例子

[java] view plaincopy
  1. <span style="font-size:16px;">package test;  
  2.   
  3. import java.io.File;  
  4. import java.io.FilenameFilter;  
  5. import java.util.Arrays;  
  6. import java.util.Scanner;  
  7. import java.util.regex.Pattern;  
  8.   
  9. /** 
  10.  * File代表文件和目录,静态域有:与系统有关的路径分隔符、与系统有关的默认名称分隔符。 
  11.  * 主要操作有:创建文件或目录、删除文件、给文件设定属性、返回指定目录下的文件列表、 
  12.  *          返回过滤后的文件列表、 检测文件是否存在、是否隐藏、是否是目录还是文件、 
  13.  *          返回文件名称和路径 
  14.  *  
  15.  * @author Touch 
  16.  * 
  17.  */  
  18. public class FileDemo {  
  19.     /* 
  20.      * 查找指定路径下的匹配regex的文件 
  21.      */  
  22.     public String[] find(String path, final String regex) {  
  23.         File file = new File(path);  
  24.         //匿名内部类  
  25.         return file.list(new FilenameFilter() {  
  26.             private Pattern pattern = Pattern.compile(regex);  
  27.             @Override  
  28.             public boolean accept(File dir, String name) {  
  29.                 // TODO Auto-generated method stub  
  30.                 return pattern.matcher(name).matches();  
  31.             }  
  32.         });  
  33.     }  
  34.   
  35.     public static void main(String[] args) {  
  36.         String path = null;  
  37.         String key = null;  
  38.         String regex = null;  
  39.         int choice = 1;  
  40.         Scanner scanner = new Scanner(System.in);  
  41.         System.out.println("please input the file path:");  
  42.         path = scanner.next();  
  43.         System.out.println("please input key:");  
  44.         key = scanner.next();  
  45.         System.out.println("choise:\n0:匹配以" + key + "为后缀的文件\n1:匹配包含" + key  
  46.                 + "的文件");  
  47.         if ((choice = scanner.nextInt()) == 0)  
  48.             regex = ".*\\." + key;  
  49.         else  
  50.             regex = ".*" + key + ".*";  
  51.         String[] list;  
  52.         list = new FileDemo().find(path, regex);  
  53.         System.out.println(Arrays.deepToString(list));  
  54.         //返回指定路径下的目录列表  
  55.         File[] fileList = new File(path).listFiles();  
  56.         for (File file : fileList) {  
  57.             if (file.isDirectory()) {  
  58.                 list = new FileDemo().find(file.getPath(), regex);  
  59.                 System.out.println(Arrays.deepToString(list));  
  60.             }  
  61.         }  
  62.     }  
  63.   
  64. }  
  65. </span>  

 

2、看完这个例子,是不是可以写个工具类呢,用于搜索指定路径下的所有文件或者目录,当然也可以输入正则表达式,这样就可以筛选出我们想要的文件(如有时候我们只需要.java文件或者.txt文件)


 

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. import java.io.File;  
  4. import java.util.ArrayList;  
  5. import java.util.List;  
  6.   
  7. /** 
  8.  * FileDirectory类用于查找指定根目录下的所有文件和目录 可以通过正则表达式对要查找的 文件及目录进行筛选 
  9.  *  
  10.  * @author Touch 
  11.  */  
  12. public final class SearchFile {  
  13.     // 存放文件  
  14.     private List<File> fileList = new ArrayList<File>();  
  15.     // 存放目录  
  16.     private List<File> directoryList = new ArrayList<File>();  
  17.     // 存放文件和目录  
  18.     private List<File> list = new ArrayList<File>();  
  19.     private File file;// 目录  
  20.     private String regex;// 正则表达式  
  21.   
  22.     public SearchFile(String path) {  
  23.         file = new File(path);  
  24.         this.regex = ".*";  
  25.     }  
  26.   
  27.     public SearchFile(File file) {  
  28.         this.file = file;  
  29.         this.regex = ".*";  
  30.     }  
  31.   
  32.     public SearchFile(String path, String regex) {  
  33.         file = new File(path);  
  34.         this.regex = regex;  
  35.     }  
  36.   
  37.     public SearchFile(File file, String regex) {  
  38.         this.file = file;  
  39.         this.regex = regex;  
  40.     }  
  41.   
  42.     // 返回当前目录下的所有文件及子目录  
  43.     public List<File> files() {  
  44.         File[] files = file.listFiles();  
  45.         List<File> list = new ArrayList<File>();  
  46.         for (File f : files)  
  47.             if (f.getName().matches(regex))  
  48.                 list.add(f);  
  49.         return list;  
  50.     }  
  51.   
  52.     // 返回该根目录下的所有文件  
  53.     public List<File> allFiles() {  
  54.         if (list.isEmpty())  
  55.             search(file);  
  56.         return fileList;  
  57.     }  
  58.   
  59.     // 返回该根目录下的所有子目录  
  60.     public List<File> allDirectory() {  
  61.         if (list.isEmpty())  
  62.             search(file);  
  63.         return directoryList;  
  64.     }  
  65.   
  66.     // 返回该根目录下的所有文件及子目录  
  67.     public List<File> allFilesAndDirectory() {  
  68.         if (list.isEmpty())  
  69.             search(file);  
  70.         return list;  
  71.     }  
  72.   
  73.     // 递归搜索当前目录下的所有文件及目录  
  74.     private void search(File file) {  
  75.         File[] files = file.listFiles();  
  76.         if (files == null || files.length == 0)  
  77.             return;  
  78.         for (File f : files) {  
  79.             if (f.getName().matches(regex))  
  80.                 list.add(f);  
  81.             if (f.isFile() && f.getName().matches(regex))  
  82.                 fileList.add(f);  
  83.             else {  
  84.                 if (f.getName().matches(regex))  
  85.                     directoryList.add(f);  
  86.                 search(f);  
  87.             }  
  88.         }  
  89.     }  
  90. }  
  91. </span>  


3、测试

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. import java.io.File;  
  4. import java.util.List;  
  5.   
  6. public class TestSearchFile {  
  7.     public static void main(String[] args) {  
  8.         System.out.println("-------- 指定目录中所有文件及子目录-------");  
  9.         List<File> list = (List<File>) new SearchFile(  
  10.                 "G:/java/workspace/test/file").files();  
  11.         for (File file : list)  
  12.             System.out.println(file.getName());  
  13.         System.out.println("--------指定目录中以txt为后缀的文件------");  
  14.         list = (List<File>) new SearchFile("G:/java/workspace/test/file",  
  15.                 ".*\\.txt").files();  
  16.         for (File file : list)  
  17.             System.out.println(file.getName());  
  18.         System.out.println("--------以该目录为根目录的所有文件及子目录--");  
  19.         list = (List<File>) new SearchFile("G:/java/workspace/test")  
  20.                 .allFilesAndDirectory();  
  21.         for (File file : list)  
  22.             System.out.println(file.getName());  
  23.     }  
  24. }  
  25. </span>  


 

4、结果:

-------- 指定目录中所有文件及子目录-------
aa.data
bb.dat
object
test.txt
test1.txt
test2.txt
test3.txt
test4.txt
test5
--------指定目录中以txt为后缀的文件------
test.txt
test1.txt
test2.txt
test3.txt
test4.txt
--------以该目录为根目录的所有文件及子目录--
.classpath
.project
.settings
org.eclipse.jdt.core.prefs
bin
http
PassWord.class
Test.class
mine
util
SearchFile.class
TestSearchFile.class
test
A.class
ArraysDemo.class
B.class
ByteArrayInputStreamDemo.class
DataInputStreamAndByteArrayInputStreamDemo.class
DataInputStreamDemo.class
DeepCloneDemo.class
FileDemo$1.class
FileDemo.class
FileInputStreamDemo.class


IO系统文件读写工具类

几个文件读写的工具类:文本文件读写、二进制文件读写、对象读写。其中对象读写工具类有错误,在试图进行多个对象读取时,读第二个对象就抛出异常,这是为什么?此外怎样把一个存放对象的文件中所有的对象读出来?

这个问题已经解决,非常感谢Aguo的文章:自定义ObjectOutputStream,解决追加写入后,读取错误的问题 。在这篇文章中我找到了答案,同时对作者的源代码添加了一些注解。解决方案请看文章最后。

1、文本文件读写工具类

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.BufferedWriter;  
  5. import java.io.FileReader;  
  6. import java.io.FileWriter;  
  7. import java.io.IOException;  
  8.   
  9. /** 
  10.  * 此工具类用于文本文件的读写 
  11.  *  
  12.  * @author Touch 
  13.  */  
  14. public class TextFile {  
  15.     // 读取指定路径文本文件  
  16.     public static String read(String filePath) {  
  17.         StringBuilder str = new StringBuilder();  
  18.         BufferedReader in = null;  
  19.         try {  
  20.             in = new BufferedReader(new FileReader(filePath));  
  21.             String s;  
  22.             try {  
  23.                 while ((s = in.readLine()) != null)  
  24.                     str.append(s + '\n');  
  25.             } finally {  
  26.                 in.close();  
  27.             }  
  28.         } catch (IOException e) {  
  29.             // TODO Auto-generated catch block  
  30.             e.printStackTrace();  
  31.         }  
  32.         return str.toString();  
  33.     }  
  34.   
  35.     // 写入指定的文本文件,append为true表示追加,false表示重头开始写,  
  36.     //text是要写入的文本字符串,text为null时直接返回  
  37.     public static void write(String filePath, boolean append, String text) {  
  38.         if (text == null)  
  39.             return;  
  40.         try {  
  41.             BufferedWriter out = new BufferedWriter(new FileWriter(filePath,  
  42.                     append));  
  43.             try {  
  44.                 out.write(text);  
  45.             } finally {  
  46.                 out.close();  
  47.             }  
  48.         } catch (IOException e) {  
  49.             // TODO Auto-generated catch block  
  50.             e.printStackTrace();  
  51.         }  
  52.     }  
  53. }  
  54. </span>  

 

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. public class TestTextFile {  
  4.     public static void main(String[] args) {  
  5.         TextFile.write("file/textfile.txt"false,  
  6.                 "这是一个文本文件的读写测试\nTouch\n刘海房\n男\n");  
  7.         TextFile.write("file/textfile.txt"true"武汉工业学院\n软件工程");  
  8.         System.out.println(TextFile.read("file/textfile.txt"));  
  9.     }  
  10. }  
  11. </span>  

 

2、二进制文件读写工具类

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.BufferedOutputStream;  
  5. import java.io.FileInputStream;  
  6. import java.io.FileOutputStream;  
  7. import java.io.IOException;  
  8.   
  9. /** 
  10.  * 此工具类用于二进制文件的读写 
  11.  *  
  12.  * @author Touch 
  13.  */  
  14. public class BinaryFile {  
  15.     // 把二进制文件读入字节数组,如果没有内容,字节数组为null  
  16.     public static byte[] read(String filePath) {  
  17.         byte[] data = null;  
  18.         try {  
  19.             BufferedInputStream in = new BufferedInputStream(  
  20.                     new FileInputStream(filePath));  
  21.             try {  
  22.                 data = new byte[in.available()];  
  23.                 in.read(data);  
  24.             } finally {  
  25.                 in.close();  
  26.             }  
  27.         } catch (IOException e) {  
  28.             e.printStackTrace();  
  29.         }  
  30.         return data;  
  31.     }  
  32.   
  33.     // 把字节数组为写入二进制文件,数组为null时直接返回  
  34.     public static void write(String filePath, byte[] data) {  
  35.         if (data == null)  
  36.             return;  
  37.         try {  
  38.             BufferedOutputStream out = new BufferedOutputStream(  
  39.                     new FileOutputStream(filePath));  
  40.             try {  
  41.                 out.write(data);  
  42.             } finally {  
  43.                 out.close();  
  44.             }  
  45.         } catch (IOException e) {  
  46.             e.printStackTrace();  
  47.         }  
  48.     }  
  49. }  
  50. </span>  


 

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. import java.util.Arrays;  
  4.   
  5. public class TestBinaryFile {  
  6.     public static void main(String[] args) {  
  7.         BinaryFile.write("file/binaryfile.dat"new byte[] { 123456,  
  8.                 78910'a''b''c' });  
  9.         byte[] data = BinaryFile.read("file/binaryfile.dat");  
  10.         System.out.println(Arrays.toString(data));  
  11.     }  
  12. }  
  13. </span>  


 

3、对象读写工具类(有问题,在读取多个对象时有问题,怎样把一个对象文件中的所有对象读出来?)

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. import java.io.FileInputStream;  
  4. import java.io.FileOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.ObjectInputStream;  
  7. import java.io.ObjectOutputStream;  
  8.   
  9. /** 
  10.  * 此类用于对象的读写 
  11.  *  
  12.  * @author Touch 
  13.  */  
  14. public class ObjectFile {  
  15.     // 把一个对象写入文件,isAppend为true表示追加方式写,false表示重新写  
  16.     public static void write(String filePath, Object o, boolean isAppend) {  
  17.         if (o == null)  
  18.             return;  
  19.         try {  
  20.             ObjectOutputStream out = new ObjectOutputStream(  
  21.                     new FileOutputStream(filePath, isAppend));  
  22.             try {  
  23.                 out.writeObject(o);  
  24.             } finally {  
  25.                 out.close();  
  26.             }  
  27.         } catch (IOException e) {  
  28.             e.printStackTrace();  
  29.         }  
  30.     }  
  31.   
  32.     // 把一个对象数组写入文件,isAppend为true表示追加方式写,false表示重新写  
  33.     public static void write(String filePath, Object[] objects, boolean isAppend) {  
  34.         if (objects == null)  
  35.             return;  
  36.         try {  
  37.             ObjectOutputStream out = new ObjectOutputStream(  
  38.                     new FileOutputStream(filePath, isAppend));  
  39.             try {  
  40.                 for (Object o : objects)  
  41.                     out.writeObject(o);  
  42.             } finally {  
  43.                 out.close();  
  44.             }  
  45.         } catch (IOException e) {  
  46.             e.printStackTrace();  
  47.         }  
  48.     }  
  49.   
  50.     // 读取对象,返回一个对象  
  51.     public static Object read(String filePath) {  
  52.         Object o = null;  
  53.         try {  
  54.             ObjectInputStream in = new ObjectInputStream(new FileInputStream(  
  55.                     filePath));  
  56.             try {  
  57.                 o = in.readObject();  
  58.             } finally {  
  59.                 in.close();  
  60.             }  
  61.         } catch (Exception e) {  
  62.             e.printStackTrace();  
  63.         }  
  64.         return o;  
  65.     }  
  66.   
  67.     // 读取对象,返回一个对象数组,count表示要读的对象的个数  
  68.     public static Object[] read(String filePath, int count) {  
  69.         Object[] objects = new Object[count];  
  70.         try {  
  71.             ObjectInputStream in = new ObjectInputStream(new FileInputStream(  
  72.                     filePath));  
  73.             try {  
  74.                 for (int i = 0; i < count; i++) {  
  75.                     //第二次调用in.readObject()就抛出异常,这是为什么?  
  76.                     objects[i] = in.readObject();  
  77.                 }  
  78.             } finally {  
  79.                 in.close();  
  80.             }  
  81.         } catch (Exception e) {  
  82.             e.printStackTrace();  
  83.         }  
  84.         return objects;  
  85.     }  
  86. }  
  87. </span>  


 

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class TestObjectFile {  
  6.     public static void main(String[] args) {  
  7.         ObjectFile.write("file/object1"new Person(), false);  
  8.         ObjectFile.write("file/object1"new Person(), true);  
  9.         ObjectFile.write("file/object1"new Person[] { new Person("Touch"1),  
  10.                 new Person("Rainbow"0), new Person() }, true);  
  11.         for (Object o : ObjectFile.read("file/object1"5))  
  12.             ((Person) o).display();  
  13.     }  
  14. }  
  15.   
  16. class Person implements Serializable {  
  17.     private String name = "刘海房";  
  18.     private int sex = 0;  
  19.   
  20.     Person(String name, int sex) {  
  21.         this.name = name;  
  22.         this.sex = sex;  
  23.     }  
  24.   
  25.     Person() {  
  26.     }  
  27.   
  28.     void display() {  
  29.         System.out.println("my name is :" + name);  
  30.         String s = (sex == 0) ? "男" : "女";  
  31.         System.out.println("性别:" + s);  
  32.     }  
  33. }</span>  


4、对象读写工具类(解决了3中的问题,能够写入及读取多个对象)

          3中到底问题出在哪呢?先来看一段ObjectOutputStream构造方法的源代码,此源代码来自jdk1.6版。

[java] view plaincopy
  1. <span style="font-size:16px;">    public ObjectOutputStream(OutputStream out) throws IOException {  
  2.     verifySubclass();  
  3.     bout = new BlockDataOutputStream(out);  
  4.     handles = new HandleTable(10, (float3.00);  
  5.     subs = new ReplaceTable(10, (float3.00);  
  6.     enableOverride = false;  
  7.     </span><span style="font-size:16px;"><span style="color:#ff0000;">writeStreamHeader();  
  8. </span> bout.setBlockDataMode(true);  
  9.         if (extendedDebugInfo) {  
  10.         debugInfoStack = new DebugTraceInfoStack();  
  11.     } else {  
  12.         debugInfoStack = null;  
  13.         }     
  14.     }</span>  


这段代码中我们只需要关注writeStreamHeader();方法,这个方法在源代码中的解释是

[java] view plaincopy
  1. <span style="font-size:16px;"/** 
  2.      * The writeStreamHeader method is provided so subclasses can append or 
  3.      * prepend their own header to the stream.  It writes the magic number and 
  4.      * version to the stream. 
  5.      * 
  6.      * @throws  IOException if I/O errors occur while writing to the underlying 
  7.      *      stream 
  8.      */</span>  

也就是说我们打开(new)一个ObjectOutputStream的时候,这个ObjectOutputStream流中就已经被写入了一些信息,这些信息会写入到我们的文件中。在第一次写入文件时,这些头部信息时需要的,因为ObjectInputStream读的时候会帮我们过滤掉。但是当我们追加写入一个文件时,这些头部信息也会写入文件中,读取的时候只会把文件第一次出现的头部信息过滤掉,并不会把文件中间的头部信息也过滤掉,这就是问题的根源所在。

      怎么解决呢?正如lichong_87提到的

      一、可以在每次写入的时候把文件中所有对象读出来,然后重新写入,这种方法效率比较低。

      二、如果不是第一次写入文件,在写入时去掉头部信息,怎么去掉呢?头部信息是在writeStreamHeader();方法中写入的,所以我们可以通过继承ObjectOutputStream来覆盖这个方法,如果不是第一次写入文件,这个方法什么也不做。

     下面是第二种解决方案的源代码及测试

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util.io;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.ObjectOutputStream;  
  6. import java.io.OutputStream;  
  7.   
  8. /** 
  9.  * 此类继承ObjectOutputStream,重写writeStreamHeader()方法,以实现追加写入时去掉头部信息 
  10.  */  
  11. public class MyObjectOutputStream extends ObjectOutputStream {  
  12.     private static File f;  
  13.   
  14.     // writeStreamHeader()方法是在ObjectOutputStream的构造方法里调用的  
  15.     // 由于覆盖后的writeStreamHeader()方法用到了f。如果直接用此构造方法创建  
  16.     // 一个MyObjectOutputStream对象,那么writeStreamHeader()中的f是空指针  
  17.     // 因为f还没有初始化。所以这里采用单态模式  
  18.     private MyObjectOutputStream(OutputStream out, File f) throws IOException,  
  19.             SecurityException {  
  20.         super(out);  
  21.     }  
  22.   
  23.     // 返回一个MyObjectOutputStream对象,这里保证了new MyObjectOutputStream(out, f)  
  24.     // 之前f已经指向一个File对象  
  25.     public static MyObjectOutputStream newInstance(File file, OutputStream out)  
  26.             throws IOException {  
  27.         f = file;// 本方法最重要的地方:构建文件对象,两个引用指向同一个文件对象  
  28.         return new MyObjectOutputStream(out, f);  
  29.     }  
  30.   
  31.     @Override  
  32.     protected void writeStreamHeader() throws IOException {  
  33.         // 文件不存在或文件为空,此时是第一次写入文件,所以要把头部信息写入。  
  34.         if (!f.exists() || (f.exists() && f.length() == 0)) {  
  35.             super.writeStreamHeader();  
  36.         } else {  
  37.             // 不需要做任何事情  
  38.         }  
  39.     }  
  40. }  
  41. </span>  


 

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util.io;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.ObjectInputStream;  
  8.   
  9. /** 
  10.  * 此类用于对象的读写 
  11.  *  
  12.  * @author Touch 
  13.  */  
  14. public class ObjectFile {  
  15.     // 把一个对象写入文件,isAppend为true表示追加方式写,false表示重新写  
  16.     public static void write(String filePath, Object o, boolean isAppend) {  
  17.         if (o == null)  
  18.             return;  
  19.         try {  
  20.             File f = new File(filePath);  
  21.             MyObjectOutputStream out = MyObjectOutputStream.newInstance(f,  
  22.                     new FileOutputStream(f, isAppend));  
  23.             try {  
  24.                 out.writeObject(o);  
  25.             } finally {  
  26.                 out.close();  
  27.             }  
  28.         } catch (IOException e) {  
  29.             e.printStackTrace();  
  30.         }  
  31.     }  
  32.   
  33.     // 把一个对象数组写入文件,isAppend为true表示追加方式写,false表示重新写  
  34.     public static void write(String filePath, Object[] objects, boolean isAppend) {  
  35.         if (objects == null)  
  36.             return;  
  37.         try {  
  38.             File f = new File(filePath);  
  39.             MyObjectOutputStream out = MyObjectOutputStream.newInstance(f,  
  40.                     new FileOutputStream(f, isAppend));  
  41.             try {  
  42.                 for (Object o : objects)  
  43.                     out.writeObject(o);  
  44.             } finally {  
  45.                 out.close();  
  46.             }  
  47.         } catch (IOException e) {  
  48.             e.printStackTrace();  
  49.         }  
  50.     }  
  51.   
  52.     // 读取对象,返回一个对象  
  53.     public static Object read(String filePath) {  
  54.         Object o = null;  
  55.         try {  
  56.             ObjectInputStream in = new ObjectInputStream(new FileInputStream(  
  57.                     filePath));  
  58.             try {  
  59.                 o = in.readObject();  
  60.             } finally {  
  61.                 in.close();  
  62.             }  
  63.         } catch (Exception e) {  
  64.             e.printStackTrace();  
  65.         }  
  66.         return o;  
  67.     }  
  68.   
  69.     // 读取对象,返回一个对象数组,count表示要读的对象的个数  
  70.     public static Object[] read(String filePath, int count) {  
  71.         Object[] objects = new Object[count];  
  72.         try {  
  73.             ObjectInputStream in = new ObjectInputStream(new FileInputStream(  
  74.                     filePath));  
  75.             try {  
  76.                 for (int i = 0; i < count; i++) {  
  77.                       
  78.                     objects[i] = in.readObject();  
  79.                 }  
  80.             } finally {  
  81.                 in.close();  
  82.             }  
  83.         } catch (Exception e) {  
  84.             e.printStackTrace();  
  85.         }  
  86.         return objects;  
  87.     }  
  88. }  
  89. </span>  


 

[java] view plaincopy
  1. <span style="font-size:16px;">package mine.util.io;  
  2.   
  3. import java.io.Serializable;  
  4.   
  5. public class TestObjectFile {  
  6.     public static void main(String[] args) {  
  7.         ObjectFile.write("file/t.dat"new Person(), false);  
  8.         ObjectFile.write("file/t.dat"new Person(), true);  
  9.         ObjectFile.write("file/t.dat"new Person[] { new Person("Touch"1),  
  10.                 new Person("Rainbow"0), new Person() }, true);  
  11.         for (Object o : ObjectFile.read("file/t.dat"5))  
  12.             ((Person) o).display();  
  13.     }  
  14. }  
  15.   
  16. class Person implements Serializable {  
  17.     private static final long serialVersionUID = 1L;  
  18.     private String name = "刘海房";  
  19.     private int sex = 0;  
  20.   
  21.     Person(String name, int sex) {  
  22.         this.name = name;  
  23.         this.sex = sex;  
  24.     }  
  25.   
  26.     Person() {  
  27.     }  
  28.   
  29.     void display() {  
  30.         System.out.println("my name is :" + name);  
  31.         String s = (sex == 0) ? "男" : "女";  
  32.         System.out.println("性别:" + s);  
  33.     }  
  34. }</span>  


运行结果:

my name is :刘海房
性别:男
my name is :刘海房
性别:男
my name is :Touch
性别:女
my name is :Rainbow
性别:男
my name is :刘海房
性别:男

 

java异常机制、异常栈、异常处理方式、异常链、异常丢失

1、java标准异常概述

Throwable表示任何可以作为异常被抛出的类,有两个子类Error和Exception。从这两个类的源代码中可以看出,这两个类并没有添加新的方法,Throwable提供了所以方法的实现。Error表示编译时和系统错误。Exception是可以被抛出的异常类。RuntimeException继承自Exception(如NullPointerException),表示运行时异常,JVM会自动抛出.

2、自定义异常类

自定义异常类方法: 通过继承Throwable或Exception。异常类的所有实现都是基类Throwable实现的,所以构造自定义异常类完全可以参考Exception和Error类。我们只要添加上自定义异常类的构造方法就可以了

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.others;  
  2.   
  3. /** 
  4.  * 自定义异常类方法 
  5.  * 1、通过继承Throwable 
  6.  * 2、通过继承Exception 
  7.  *  
  8.  * @author Touch 
  9.  */  
  10. public class MyExceptionDemo extends Exception {  
  11.   
  12.     private static final long serialVersionUID = 1L;  
  13.   
  14.     public MyExceptionDemo() {  
  15.         super();  
  16.     }  
  17.   
  18.     public MyExceptionDemo(String message) {  
  19.         super(message);  
  20.     }  
  21.   
  22.     public MyExceptionDemo(String message, Throwable cause) {  
  23.         super(message, cause);  
  24.     }  
  25.   
  26.     public MyExceptionDemo(Throwable cause) {  
  27.         super(cause);  
  28.     }  
  29. }  
  30. </span>  


 

3、异常栈及异常处理方式

可以通过try、catch来捕获异常。捕获到的异常。下面的示例演示了几种常用异常处理方式

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.others;  
  2.   
  3. import mine.util.exception.MyException;  
  4.   
  5. public class ExceptionDemo1 {  
  6.     public void f() throws MyException {  
  7.         throw new MyException("自定义异常");  
  8.     }  
  9.   
  10.     public void g() throws MyException {  
  11.         f();  
  12.     }  
  13.   
  14.     public  void h() throws MyException  {  
  15.         try {  
  16.             g();  
  17.         } catch (MyException e) {  
  18.             //1、通过获取栈轨迹中的元素数组来显示异常抛出的轨迹  
  19.             for (StackTraceElement ste : e.getStackTrace())  
  20.                 System.out.println(ste.getMethodName());  
  21.             //2、直接将异常栈信息输出至标准错误流或标准输出流  
  22.             e.printStackTrace();//输出到标准错误流  
  23.             e.printStackTrace(System.err);  
  24.             e.printStackTrace(System.out);  
  25.             //3、将异常信息输出到文件中  
  26.             //e.printStackTrace(new PrintStream("file/exception.txt"));  
  27.             //4、重新抛出异常,如果直接抛出那么栈路径是完整的,如果用fillInStackTrace()  
  28.             //那么将会从这个方法(当前是h()方法)作为异常发生的原点。  
  29.             //throw e;  
  30.             throw (MyException)e.fillInStackTrace();  
  31.         }  
  32.     }  
  33.     public static void main(String[] args) {  
  34.             try {  
  35.                 new ExceptionDemo1().h();  
  36.             } catch (MyException e) {  
  37.                 // TODO Auto-generated catch block  
  38.                 e.printStackTrace();  
  39.             }  
  40.     }  
  41. }  
  42. </span>  

运行结果:

f
g
h
main
mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7)
 at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11)
 at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16)
 at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7)
 at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11)
 at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16)
 at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo1.f(ExceptionDemo1.java:7)
 at demo.others.ExceptionDemo1.g(ExceptionDemo1.java:11)
 at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:16)
 at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)
mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo1.h(ExceptionDemo1.java:30)
 at demo.others.ExceptionDemo1.main(ExceptionDemo1.java:35)

分析上面的程序,首先main函数被调用,然后是调用h函数,再g函数、f函数,f函数抛出异常,并在h函数捕获,这时将依次从栈顶到栈底输出异常栈路径。

4、异常链

有时候我们会捕获一个异常后在抛出另一个异常,如下代码所示:

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.others;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import mine.util.exception.MyException;  
  6.   
  7. public class ExceptionDemo2 {  
  8.     public void f() throws MyException {  
  9.         throw new MyException("自定义异常");  
  10.     }  
  11.   
  12.     public void g() throws Exception  {  
  13.         try {  
  14.             f();  
  15.         } catch (MyException e) {  
  16.             e.printStackTrace();  
  17.             throw new Exception("重新抛出的异常1");  
  18.         }  
  19.     }  
  20.   
  21.     public  void h() throws IOException    {  
  22.         try {  
  23.             g();  
  24.         } catch (Exception e) {  
  25.             // TODO Auto-generated catch block  
  26.             e.printStackTrace();  
  27.             throw new IOException("重新抛出异常2");  
  28.         }  
  29.     }  
  30.     public static void main(String[] args) {  
  31.             try {  
  32.                 new ExceptionDemo2().h();  
  33.             } catch (IOException e) {  
  34.                 // TODO Auto-generated catch block  
  35.                 e.printStackTrace();  
  36.             }  
  37.     }  
  38. }  
  39. </span>  


运行结果:

mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
 at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)
java.lang.Exception: 重新抛出的异常1
 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17)
 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
 at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)
java.io.IOException: 重新抛出异常2
 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27)
 at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:32)

从结果中我们可以看出,异常栈变小了。也就是说丢失了最原始的异常信息。怎样保存最原始的异常信息呢?Throwable类中有个Throwable  cause属性,表示原始异常。通过接收cause参数的构造器可以把原始异常传递给新异常,或者通过initCause()方法。如下示例:

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.others;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import mine.util.exception.MyException;  
  6.   
  7. public class ExceptionDemo2 {  
  8.     public void f() throws MyException {  
  9.         throw new MyException("自定义异常");  
  10.     }  
  11.   
  12.     public void g() throws Exception  {  
  13.         try {  
  14.             f();  
  15.         } catch (MyException e) {  
  16.             e.printStackTrace();  
  17.             throw new Exception("重新抛出的异常1",e);  
  18.         }  
  19.     }  
  20.   
  21.     public  void h() throws IOException    {  
  22.         try {  
  23.             g();  
  24.         } catch (Exception e) {  
  25.             // TODO Auto-generated catch block  
  26.             e.printStackTrace();  
  27.             IOException io=new IOException("重新抛出异常2");  
  28.             io.initCause(e);  
  29.             throw io;  
  30.         }  
  31.     }  
  32.     public static void main(String[] args) {  
  33.             try {  
  34.                 new ExceptionDemo2().h();  
  35.             } catch (IOException e) {  
  36.                 // TODO Auto-generated catch block  
  37.                 e.printStackTrace();  
  38.             }  
  39.     }  
  40. }  
  41. </span>  


 

结果:

mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
 at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34)
java.lang.Exception: 重新抛出的异常1
 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17)
 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
 at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34)
Caused by: mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
 ... 2 more
java.io.IOException: 重新抛出异常2
 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:27)
 at demo.others.ExceptionDemo2.main(ExceptionDemo2.java:34)
Caused by: java.lang.Exception: 重新抛出的异常1
 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:17)
 at demo.others.ExceptionDemo2.h(ExceptionDemo2.java:23)
 ... 1 more
Caused by: mine.util.exception.MyException: 自定义异常
 at demo.others.ExceptionDemo2.f(ExceptionDemo2.java:9)
 at demo.others.ExceptionDemo2.g(ExceptionDemo2.java:14)
 ... 2 more

从结果中看出当获取到“重新抛出异常2的时候,同时可以输出原始异常“重新抛出的异常1“和原始异常”自定义异常,这就是异常链。

5、finally的使用

finally子句总是执行的,通常用来做一些清理工作,如关闭文件,关闭连接等

下面举几个finally的例子:

[java] view plaincopy
  1. <span style="font-size:16px;">// 读取指定路径文本文件  
  2.     public static String read(String filePath) {  
  3.         StringBuilder str = new StringBuilder();  
  4.         BufferedReader in = null;  
  5.         try {  
  6.             in = new BufferedReader(new FileReader(filePath));  
  7.             String s;  
  8.             try {  
  9.                 while ((s = in.readLine()) != null)  
  10.                     str.append(s + '\n');  
  11.             } finally {  
  12.                 in.close();  
  13.             }  
  14.         } catch (IOException e) {  
  15.             // TODO Auto-generated catch block  
  16.             e.printStackTrace();  
  17.         }  
  18.         return str.toString();  
  19.     }</span>  

分析:如果调用in = new BufferedReader(new FileReader(filePath));时发生异常,这时是一个文件路径不存在的异常,也就是说并没有打开文件,这时将会直接跳到catch块,而不会执行try...finally块(并不是finally子句)里面的语句in.close();此时不需要关闭文件。

再看一个例子,会导致异常的丢失

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.others;  
  2.   
  3. import mine.util.exception.MyException;  
  4.   
  5. public class ExceptionDemo3 {  
  6.     public void f() throws MyException {  
  7.         throw new MyException("异常1");  
  8.     }  
  9.   
  10.     public void g() throws MyException {  
  11.         throw new MyException("异常2");  
  12.     }  
  13.   
  14.     public static void main(String[] args) {  
  15.   
  16.         try {  
  17.             ExceptionDemo3 ex = new ExceptionDemo3();  
  18.             try {  
  19.                 ex.f();  
  20.             } finally {  
  21.                 ex.g();//此时捕获g方法抛出的异常,f方法抛出的异常丢失了  
  22.             }  
  23.         } catch (MyException e) {  
  24.             System.out.println(e);  
  25.         }  
  26.   
  27.     }  
  28. }  
  29. </span>  

结果:mine.util.exception.MyException: 异常2

此时异常1就丢失了
或者这样写:

[java] view plaincopy
  1. <span style="font-size:16px;">package demo.others;  
  2.   
  3. import mine.util.exception.MyException;  
  4.   
  5. public class ExceptionDemo3 {  
  6.   
  7.     public void g() throws MyException {  
  8.         throw new MyException("异常2");  
  9.     }  
  10.   
  11.     public static void main(String[] args) {  
  12.         ExceptionDemo3 ex = new ExceptionDemo3();  
  13.         try {  
  14.             ex.g();  
  15.         } finally {  
  16.             //直接return会丢失所以抛出的异常  
  17.             return;  
  18.         }  
  19.   
  20.     }  
  21. }  
  22. </span>  

6、异常的限制

(1)当覆盖方法时,只能抛出在基类方法的异常说明里列出的那些异常,有些基类的方法声明抛出异常其实并没有抛出异常,这是因为可能在其子类的覆盖方法中会抛出异常

(2)构造器可以抛出任何异常而不必理会基类构造器所抛出的异常,派生类构造器异常说明必须包含基类构造器异常说明,因为构造派生类对象时会调用基类构造器。此外,派生类构造器不能捕获基类构造器抛出的异常。



原创粉丝点击