JAVA基础--异常&IO、其他流&编码表、Properties

一、异常&IO

异常重点掌握5点:
1:异常体系
2:如何使用标准的try{}catch(){ }
3: 编译期异常的其中一种处理方式throws
4:如何自定义一个异常并注意throw和throws的区别
5: finally经典面试题
File需要掌握的功能
1:构造方法
2:成员方法
创建功能
删除功能
判断功能
获取功能
☆重要获取功能
文件过滤器
异常:程序出现了不正常的情况。

异常的体系
Throwable  
Error:严重 问题,通常出现重大问题如:运行的类不存在或者内存溢出等。是不需要处理的。
一般这种情况是需要修改代码的。
这儿的处理指的是(try{}catch(){}或者throws),出现error这样严重问题的时候
靠处理的方式是解决不了的,必须找出那个地方犯了这么严重的错误,然后修改代码,改正确了之后,
程序才能够运行起来,否则程序绝对运行不起来。
  
Exception:不严重
  1:编译期间:这个是我们需要处理的。(Exception下面 非RuntimeException 的异常)
编译期异常就是在咱们写代码的时候程序提示你,这儿以后可能会出现一些常见的问题,让咱们在写代码的时候就得针对这常见的问题
采取措施,不要等运行的时候出现了并且报出了哪出的错再去解决,因为这个问题很常见,可以预防,所以Java呢为了这样提示咱们就
让咱们编译的时候都不让咱们编译通过,必须要采取措施,而我们采取的措施一个就是用try{}catch(){} 另一个就是不用管这个异常啦
直接抛给虚拟机把,这两种方式都证明咱们开发人员知道这儿可能会出现异常了并采取措施了。
所以说编译期异常的处理方式有两种

1)声明异常(就是抛出异常)
在方法声明的后面(即大括号前面):throws 异常类型,不明确要怎么处理的时候
比如:

[java]  view plain  copy
  1. public static void main(String[] args) throws FileNotFoundException  {  
  2.                             // 编译时期  
  3.                             FileInputStream fis = new FileInputStream("a.txt");  
  4.                         }     

2)try{
  编译期异常代码
    }catch(异常类名 变量名){
  异常处理代码。
    }

  2:运行期间:这个是我们不需要处理,但是也可以处理  (RuntimeException下的异常)

1)如果不处理,java就会用jvm会采用自动的处理方式,
它就把异常的类型,原因,位置直接显示在了控制台。并且退出当前线程(可以理解为退出虚拟机)
同时后面的代码是不能执行的。
2)如果处理,   我们会采用try{}catch(){}
try{
  可能发生问题的代码。
  }catch(异常类名 变量名){
  异常处理代码。
  }

①:一个代码中,有多个问题,怎么解决呢?
 A:一个个用异常处理方案解决。(也就是写多个try{}catch(){})
 B:针对所有问题,写一个try...catch代码。
  try{}catch(){}catch(){}...
针对多个异常,写一个try的代码,catch里面会不会有顺序问题呢?
*如果异常是平级关系,没有顺序问题。
*如果异常存在着子父关系,父一定要放在最后。
代码:
[java]  view plain  copy
  1. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                </span><span style="font-family: Arial, Helvetica, sans-serif;">try {</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                  // ArithmeticException</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                 int a = 10;</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                    int b = 2;</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                 // int b = 0;</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                  // ArrayIndexOutOfBoundsException</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                  System.out.println(a / b);</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                 // System.out.println(arr[3]);</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                 int[] arr = { 1, 2, 3 };</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                   // 这里又出现了一个问题,这里很明显是一个空指针问题。</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                   System.out.println(arr[2]);</span></div><div style="text-align: left;"></div>  
  2. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                    String s = null;</span></div>                  // 假设我们忘了,也就是说我们不知道这是一个什么异常。  
  3.                    // 怎么处理呢?  
  4. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                    System.out.println("over");</span></div>                    System.out.println(s.length());  
  5.                  // 继续操作  
  6. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                } catch (ArithmeticException ae) {</span></div>                 } catch (ArrayIndexOutOfBoundsException ae) {  
  7.                     System.out.println("数组越界异常");  
  8. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                }</span></div>                  System.out.println("除数不能为0");  
  9.                     } catch (Exception e) {  
  10.                     System.out.println("空指针问题");  
  11. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                            </span></div>  
写多个catch(){}我们觉得很麻烦这时候就有了JDK7的新特性
JDK7新特性:多个catch用一个catch替代。 不是说多个catch的内容,用一个Exception处理。
 格式:
  catch(异常1 | 异常2 | 异常3 ... 变量名){}
代码:
[java]  view plain  copy
  1. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">                                    </span>try {</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                     // ArithmeticException</span></div>                 int a = 10;  
  2. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                        int b = 2;</span></div>                 // int b = 0;  
  3. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                        // ArrayIndexOutOfBoundsException</span></div>                  System.out.println(a / b);  
  4.   
  5. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                        // System.out.println(arr[3]);</span></div>                 int[] arr = { 1, 2, 3 };  
  6.                     System.out.println(arr[2]);  
  7.   
  8. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                        // 假设我们忘了,也就是说我们不知道这是一个什么异常。</span></div>  
  9.                     // 这里又出现了一个问题,这里很明显是一个空指针问题。  
  10.                     // 怎么处理呢?  
  11. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                        // 继续操作</span></div>                    String s = null;  
  12.                     System.out.println(s.length());  
  13. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                    } catch (ArrayIndexOutOfBoundsException | ArithmeticException</span></div>                  System.out.println("over");  
  14.                     | NullPointerException ae) {  
  15. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                    }</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                      ae.printStackTrace();</span></div>  

②:我们一直在处理异常的时候都是打印的一句话,虽然我们提示了有错误,但是告诉开发人员是哪一行代码出错了吗?
告诉开发人员是哪个异常了吗?没有吧? 那这样的话,不利于开发人员对代码进行维护,所以我们就有了
标准的异常catch代码,既能打印出异常消息,显示出哪一行出的错,又能不影响后面的代码执行

首先介绍:Throwable中的方法:
  public String getMessage():返回的是异常的消息字符串。
  public String toString():返回异常的简单描述信息。
  全路径类名 : 消息字符串
public void printStackTrace():把错误信息显示在控制台。
学完了printStackTrace()后,就学习了catch标准代码
try{
  可能有问题的代码
}catch(异常类名 变量名){
  变量名.printStackTrace();
}finally{
释放资源代码。(数据库,IO)
}
代码:
[java]  view plain  copy
  1. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                            </span><span style="font-family: Arial, Helvetica, sans-serif;">int a = 10;</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                            int b = 0;</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                         try {</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                              System.out.println(a / b);  </span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                           } catch (ArithmeticException ae) {                                                              </span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                               ae.printStackTrace();</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                          }</span></div>  
3)如果处理运行期异常,我们还可以采用Throws 抛出异常,但是我们一般不用(为什么?请看下面解释)

编译期异常:Exception下面 非RuntimeException 的异常
运行期异常:RuntimeException下的异常

如果是运行期异常的话我们抛出,和不抛出有区别吗?是不是一样的啊?而且只要运行时出现异常的话,抛出和不抛出
后面的代码都不会再继续执行了,那么我们为什么有个抛出异常这种处理方式呢?这就又引出了编译期异常,
编译器异常就是在咱们写代码的时候程序提示你,这儿以后可能会出现一些常见的问题,让咱们在写代码的时候就得针对这常见的问题
采取措施,不要等运行的时候出现了并且报出了哪出的错再去解决,因为这个问题很常见,可以预防,所以java呢为了这样提示咱们就
让咱们编译的时候都不让咱们编译通过,必须要采取措施,而我们采取的措施一个就是用try{}catch(){} 另一个就是不用管这个异常啦
直接抛给虚拟机把,这两种方式都证明咱们开发人员知道这儿可能会出现异常了并采取措施了。 所以抛出异常是给谁准备的?给编译器异常
准备的? 运行期异常虽然能用,但是没啥实际意义,所以运行期异常我们一般还是用try{}catch(){}

3:自定义异常
对于JDK里面提供给我们的异常对于咱们基础班写程序肯定是够用了,但是对于项目中某些业务的需要,是不够用的,
需要我们自己定义一些异常,

1)先定义一个类
2)继承Exception或者RuntimeException。
代码:
[java]  view plain  copy
  1. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                                  public class MyException extends Exception {</span></div>         <span style="white-space:pre">    </span>public MyException(String message) {  
  2.             <span style="white-space:pre">    </span> super(message);  
  3.             }  
  4. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                        }</span></div>  
3)写一个有参构造方法
public MyException(String message) {
super(message);
}
4)在不满足条件的代码里面直接throw异常
代码:
[java]  view plain  copy
  1. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;"><span style="white-space:pre">                        </span>public class Teacher {</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                            public void checkScore(int score) throws MyException {</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                             if (score < 0 || score > 100) {</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                  MyException my = new MyException("分数不在指定范围内");</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                 // System.out.println("分数错误");</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                 throw my;</span></div>                              } else {  
  2. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                            }</span></div>                                  System.out.println("分数正确");  
  3. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                }</span></div>  
测试类代码:
[java]  view plain  copy
  1. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                        </span><span style="font-family: Arial, Helvetica, sans-serif;">public static void main(String[] args) {</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                           Scanner sc = new Scanner(System.in);</span></div>           <span style="white-space:pre">    </span>System.out.println("请输入学生成绩:");  
  2. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                            Teacher t = new Teacher();</span></div>             int score = sc.nextInt();  
  3.                 try {  
  4. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                                System.out.println(e.getMessage());</span></div>                t.checkScore(score);  
  5.             } catch (MyException e) {  
  6.                                   
  7. <div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                        }</span></div><div style="text-align: left;"><span style="font-family: Arial, Helvetica, sans-serif;">                          }</span></div>  
4:final和finally和finalize经典题型
final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。
因此一个类不能既被声明为 abstract的,又被声明为final的。
将变量或方法声明为final,可以保证它们在使用中不被改变。
被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
被声明为final的方法也同样只能使用,不能重写。
finally—再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,
那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
finalize—方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。
它是在 Object 类中定义的,因此所有的类都继承了它。
子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。
finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
情况1:try{} catch(){}finally{} return;???? 显然程序按顺序执行。
情况2:try{ return; }catch(){} finally{} return;????????? 
程序执行try块中return之前(包括return语句中的表达式运算)
代码;再执行finally块,最后执行try中return;?????
finally块之后的语句return,因为程序在try中已经return所以不再执行。
情况3:try{ } catch(){return;} finally{} return;??程序先执行try,如果遇到异常执行catch块,
有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,
再执行finally语句中全部代码,???????????????????
最后执行catch块中return. finally之后也就是4处的代码不再执行。
无异常:执行完try再finally再return.
情况4:try{ return; }catch(){} finally{return;}程序执行try块中return之前
(包括return语句中的表达式运算)代码; 再执行finally块,
因为finally块中有return所以提前退出。
情况5:try{} catch(){return;}finally{return;}? 程序执行catch块中return之前
(包括return语句中的表达式运算)代码;再执行finally块,
因为finally块中有return所以提前退出。
情况6:try{ return;}catch(){return;} finally{return;} 程序执行try块中return之前
(包括return语句中的表达式运算)代码 
有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;?
则再执行finally块,因为finally块中有return所以提前退出。
无异常:则再执行finally块,因为finally块中有return所以提前退出。
最终结论:任何执行try 或者catch中的return语句之前,都会先执行finally语句,
如果finally存在的话。如果finally中有return语句,那么程序就return了,
所以finally中的return是一定会被return的,
?编译器把finally中的return实现为一个warning。

代码:
[java]  view plain  copy
  1. <span style="white-space:pre">                    </span>private static int method3() {  
  2.                         int a = 10;  
  3.                         try {  
  4.                             System.out.println(a / 0);  
  5.                             System.out.println("a1:" + a);  
  6.                         } catch (ArithmeticException ae) {  
  7.                             System.out.println("a2:" + a); // a2:10  
  8.                             a = 20;  
  9.                             return a; //这个时候,在内存中就会有一个路径产生,该路径返回值是20.  
  10.                                       //但是,它看到了finally代码块,所以,继续执行finally里面的内容         
  11.                                       //当finally里面结束后,会回到以前的执行路径。  
  12.                         } finally {  
  13.                             System.out.println("a3:" + a); // a3:20  
  14.                             a = 30;                           
  15.                         }  
  16.                     }<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">                                  </span>  
IO流的概述
复制粘贴 上传下载
IO流的分类
按流向
输入流
输出流
按操作的数据
字符流
字节流

文件类File类
构造方法:
 File(String pathname):根据指定的路径创建File对象。
 File(String parent, String child):根据指定的父文件夹和子文件或者文件夹创建File对象
 File(File parent, String child):根据指定的父文件夹对象和子文件或者文件夹创建File对象
 代码:
// 方式1
File file = new File("d:\\a.txt");
File file2 = new File("d:\\aaa");

// 方式2
File file3 = new File("d:\\", "a.txt");
File file4 = new File("d:\\", "aaa");

// 方式3
File file5 = new File("d:\\");
File file6 = new File(file5, "a.txt");
File file7 = new File(file5, "aaa");

创建功能:
   创建文件:public boolean createNewFile()
       如果指定的文件不存在,就创建。如果存在,就不创建。
  创建文件夹:public boolean mkdir()
   创建指定的目录,如果存在,就不创建。
    public boolean mkdirs()
  创建指定的目录,如果存储,就不创建。这个时候,如果父目录不存在,它也会自动创建。

注意:
File file5 = new File("b.txt");
System.out.println("mkdir:" + file5.mkdir());
以上代码创建的是一个"b.txt"的文件夹

绝对路径:以盘符开始的路径。
相对路径:不以盘符开始的路径。


代码:
// 创建文件
File file = new File("d:\\a.txt");
System.out.println("createNewFile:" + file.createNewFile());

// 创建文件 忘了写路径名称了,以当前项目路径所在路径为父目录
File file2 = new File("a.txt");
System.out.println("createNewFile:" + file2.createNewFile());

// 创建目录
File file3 = new File("aaa");
System.out.println("mkdir:" + file3.mkdir());

// 创建多级目录 如果想创建一个指定的目录或者文件,要求,父目录必须存在。
// File file4 = new File("bbb\\ccc");
// System.out.println("mkdir:" + file4.mkdir());

// 解决方案:
// File file5 = new File("bbb");
// File file6 = new File(file5, "ccc");
// System.out.println("mkdir:" + file5.mkdir());
// System.out.println("mkdir:" + file6.mkdir());

// 如果目录过多,这样做就太麻烦。肿么办呢?
File file4 = new File("bbb\\ccc");
System.out.println("mkdirs:" + file4.mkdirs());

删除功能:
   public boolean delete():既可以删除文件,也可以删除文件夹。取决于你使用的对象。
注意:
  A:如果你删除的目录下还有内容,那么,必须先把所有内容删除完毕后,在删除目录。
   B:java语言的删除不走回收站

代码:
[java]  view plain  copy
  1. // 需求:我要删除a.txt  
  2.         File file = new File("a.txt");  
  3.         System.out.println("delete:" + file.delete());  
  4.   
  5.   
  6.         // 需求:我要删除aaa  
  7.         File file2 = new File("aaa");  
  8.         System.out.println("delete:" + file2.delete());  
  9.   
  10.   
  11.         // 需求:我要删除bbb  
  12.         File file3 = new File("bbb");  
  13.         System.out.println("delete:" + file3.delete());  
判断功能

 boolean exists():判断file对象是否存在
 boolean isFile():判断file对象是否是文件
 boolean isDirectory():判断file对象是否是文件夹
 boolean isAbsolute():判断file对象是否是绝对路径
 boolean canRead():判断file对象是否可读
 boolean canWrite():判断file对象是否可写
 boolean isHidden():判断file对象是否隐藏

获取功能:

 String getAbsolutePath():绝对路径
 String getPath():相对路径
 String getName():文件名称
 long length():文件大小,单位是字节
 long lastModified():上次修改时间的毫秒值。

重要获取功能

 public static File[] listRoots():列出可用的系统文件根目录
 public String[] list():返回的是指定目录下所有文件或者文件夹的名称数组
 public File[] listFiles():返回的是指定目录下所有文件或者文件夹对象数组

案例:获取指定目录下(E盘下根目录)所有.mp4文件的名称,并把名称打印在控制台上.
解决方案:
文件名称过滤器:FilenameFilter
   public String[] list(FilenameFilter filter)

代码:
[java]  view plain  copy
  1. // 封装目录  
  2.         File file = new File("d:\\");  
  3.   
  4.   
  5.         // 获取满足条件的数组  
  6.         String[] strArray = file.list(new FilenameFilter() {  
  7.             @Override  
  8.             public boolean accept(File dir, String name) {  
  9.                 // 判断是否是文件,是否是以.mp4结尾  
  10.                 // System.out.println(dir + "---" + name);  
  11.                 File file = new File(dir, name); // d:\我的文档  
  12.                 boolean flag = file.isFile();  
  13.                 boolean flag2 = name.endsWith(".mp4");  
  14.                 return flag && flag2;  
  15.             }  
  16.         });  
  17.   
  18.   
  19.         // 遍历字符串数组  
  20.         for (String str : strArray) {  
  21.             System.out.println(str);  
  22.         }  
二、递归和IO流

递归:
递归定义:方法定义调用方法本身的现象。
public void show(){
show();
}

注意事项:
  A:递归一定要有出口。否则就会死递归。
  B:递归的次数不要过多。否则内存溢出。

举例:
  public void show(int n)
  {
  if(n==0)
  {
  System.exit(0);
  }
  else{
  System.out.println("hell");
  show(n-1);
  }
  }

做递归的题思路
1)找递归出口
2)找递归规律

举例:用递归求5!
出口:1!=1
规律:n!=n*(n-1)!
public static int jc(int n) {
if (n == 1) {
// 出口
return 1;
} else {
// 规律
return n * jc(n - 1);
}
}

案例:用递归求斐波那契数列

[java]  view plain  copy
  1. public static int fun(int n) {  
  2.               
  3. if (n == 1 || n == 2) {  
  4.     return 1;  
  5. else {  
  6. return fun(n - 1) + fun(n - 2);  
  7.         }  
  8.         }  
  9.       

     用递归求下列数列的第二十项的值: 1,1,2,4,7,13,24...
[java]  view plain  copy
  1. <span style="white-space:pre">            </span>private static int sum(int i) {  
  2.           
  3.                 if(i ==1){  
  4.                     return 1;  
  5.                 }else if(i==2){  
  6.                     return 1;  
  7.                 }else if(i==3){  
  8.                     return 2;  
  9.                 }else{  
  10.                     return sum(i-3) +sum(i-2)+ sum(i-1);  
  11.                 }  
  12.             }  

应用:1:在控制台输出 D:\itcast\20131130 所有的java文件的绝对路径。
[java]  view plain  copy
  1. <span style="white-space:pre">            </span>private static void showFiles(File file) {  
  2.                 // 获取该目录下的所有文件或者文件夹的File[]数组。  
  3.                 File[] fileArray = file.listFiles();  
  4.                   
  5.                 //有时候一些有权限的文件不能获取,所以fileArray有可能为null所以要加入判断  
  6.                 if(fileArray!=null){  
  7.   
  8.                     // 遍历File[]数组,获取到每一个File对象  
  9.                     for (File f : fileArray) {  
  10.                         // 判断该File对数是否是目录  
  11.                         if (f.isDirectory()) {  
  12.                             showFiles(f);  
  13.                         } else {  
  14.                             // 文件  
  15.                             if (f.getName().endsWith(".java")) {  
  16.                                 System.out.println(f.getAbsolutePath());  
  17.                             }  
  18.                         }  
  19.                     }  
  20.                 }  
  21.                   
  22.             }  

     2:删除指定的目录。(目录是带有目录或者文件的)

[java]  view plain  copy
  1. private static void deleteFiles(File file) {  
  2.             //第1步封装文件夹  
  3.             File[] fileArray = file.listFiles();//1,test_deleteFiles;   2.1,aaa_deleteFiles;   2.2,bbb_deleteFiles;   
  4.               
  5.             if (fileArray != null) {  
  6.                 //如果封装的文件夹不为空,那么就进行遍历,获得每一个文件或文件夹  
  7.                 for (File f : fileArray) {  
  8.                     if (f.isDirectory()) {  
  9.                         //如果被封装文件夹的子文件还是个文件夹,那么继续封装起来进行判断  
  10.                         deleteFiles(f);  
  11.                     } else {  
  12.                         //如果被封装起来的子文件夹正好就是个文件,那么直接删除  
  13.                         System.out.println(f.getName() + "***" + f.delete());  
  14.                     }  
  15.                 }  
  16.                   
  17.             }   
  18.             System.out.println(file.getName() + "***" + file.delete());  
  19.               
  20.             // 如果文件夹为空,直接删除. 当if语句执行完时,就表示每次封装的目录下的文件被删除完毕。  
  21.               
  22.         }  

IO流
1:字符输出流FileWriter

1)完成一个简单在指定文件中写入数据的操作的步骤
A:创建字符输出流FileWriter对象(并且传入一个你要写入的位置)
FileWriter fw = new FileWriter("a.txt");
B:调用写数据的功能
fw.write("hello,io,我来了。祝你元旦快乐。");
C:刷新缓冲区
fw.flush();
D:释放资源(jvm不会自动回收流的资源,除非你手动标记该流已成为垃圾)
fw.close();

2)对简单在指定文件中写入数据的操作提出了疑问

①为什么FileWriter没有无参构造方法?
因为写数据的时候,一定要明确写道哪里去。

②既然close()也有刷新缓冲区的作用为什么还要flush呢?(flush()和close()的区别?)
flush():只刷新缓冲区,流对象还可以继续使用。
close():先刷新缓冲区,在关闭流对象。流对象不可以继续被使用。

③难道每次调用方法的时候,都需要刷新吗?或者说,不用刷,直接等到close()来解决,行不行?
两种方法都不可取,因为每写入一个字就调用一次flush的话,如果写入大量文字的时候
这时候效率就太低了,但是如果写入大量文字在缓冲区,直接等到close()再刷新的话如果文字太多,
不及时刷新缓冲区的话,又怕会内存溢出,所以要设置刷新间隔,比如下面代码是开发中常用的
int count = 0;
for (int x = 0; x < 1000000; x++) {
fw.write("hello,林青霞" + x);
if (++count % 10000 == 0) {
fw.flush();
}
}

3)对简单在指定文件中写入数据的操作又提出了疑问

①写入数据的方式只有write(String str);这一种吗?
写入数据的方式,有5种。
write(int ch)
  write(char[] chs,int index,int len)
  write(char[] chs)
  write(String str,int index,int len)
write(String str)

②如果我想写入的文字需要换行怎么办
fw.write("hello\r\n");
fw.write("world\r\n");
fw.write("java\r\n");

③数据每次都把以前的给覆盖了,如果我想追加写入,怎么办?
构造的时候,用带两个参数的。这样就不会删除以前的文件,而是在以前的文件上追加写入
public FileWriter(String fileName,boolean append)

4)简单在指定文件中写入数据的操作里面,我们把异常抛出了,如果用try{}catch(){}来处理的话该怎么写呢?

[java]  view plain  copy
  1. <span style="white-space:pre">        </span>FileWriter fw = null;(必须初始化)  
  2.             try {  
  3.                 //把有可能报错的部分都写在try里面  
  4.                 fw = new FileWriter("d.txt");  
  5.                 fw.write("hello");  
  6.                 fw.flush();  
  7.             } catch (IOException e) {  
  8.                 e.printStackTrace();  
  9.             } finally {  
  10.                 if (fw != null) {//有可能try里面报错了,fw就是null,这时候如果不判断 下面的fw.close()就会报空指针异常  
  11.                     try {  
  12.                         fw.close();  
  13.                     } catch (IOException e) {  
  14.                         e.printStackTrace();  
  15.                     }  
  16.                 }  
  17.             }  

2:字符输入流FileReader
1) 普通字符输入流读取数据步骤:
 A:创建字符输入流对象(并且明确你要从哪个文件读数据)
FileReader fr = new FileReader("FileWriterDemo.java");
 B:调用读取数据功能,并显示
int ch = 0;
while((ch=fr.read())!=-1){//如果数据没有了,读取的时候,将返回-1
 //如果有数据则返回int类型(字符的int值),并自动移动到下一个数据位置等待读取
System.out.print((char) ch);
}
 C:释放资源
fr.close();

案例:如果D盘下有一个文件a.txt, 我们想把它复制到E盘下,并且改名为这个如何做?
用普通字符输入流读取数据来做这道题
[java]  view plain  copy
  1. <span style="white-space:pre">        </span>// 封装数据源  
  2.             FileReader fr = new FileReader("FileWriterDemo.java");  
  3.             // 封装目的地  
  4.             FileWriter fw = new FileWriter("d:\\Copy.java");  
  5.   
  6.   
  7.             // 读取数据  
  8.             int ch = 0;  
  9.             while ((ch = fr.read()) != -1) {  
  10.                 fw.write(ch);  
  11.                 fw.flush();  
  12.             }  
  13.             // 释放资源  
  14.             fw.close();  
  15.             fr.close();  

2)比较高效率的字符输入流读取数据步骤:
需要用到如下方法
public int read(char[] cbuf)
每次读取数据,把数据存储到字符数组中,返回值是实际读取长度。

A: 创建字符输入流
FileReader fr = new FileReader("FileWriterDemo.java");

B:读取数据每次读取一个数组
char[] chs = new char[1024];
int len = 0;
while ((len = fr.read(chs)) != -1) {//len表示read(chs)读取到多少个字符
   //如果实际读取长度是-1的情况,那么,说明已经读取到结尾了

System.out.print(new String(chs, 0, len));//new String(chs, 0, len) 是为了写入实际读入的数据,否则读取到最后的时候可能会有偏差
}

C:释放资源
fr.close();

案例:如果D盘下有一个文件a.txt, 我们想把它复制到E盘下,并且改名为这个如何做?
用比较高效率的字符输入流读取数据来做这道题
[java]  view plain  copy
  1. <span style="white-space:pre">        </span>// 封装数据源  
  2.             FileReader fr = new FileReader("FileWriterDemo.java");  
  3.             // 封装目的地  
  4.             FileWriter fw = new FileWriter("d:\\Copy.java");  
  5.   
  6.   
  7.               
  8.             char[] chs = new char[1024];  
  9.             int len = 0;  
  10.             while ((len = fr.read(chs)) != -1) {//读入数据  
  11.                 //写入数据.  
  12.                 fw.write(chs,0,len);  
  13.             }  
  14.   
  15.   
  16.             // 释放资源  
  17.             fw.close();  
  18.             fr.close();  

三、字符流和字节流

字符流
1:基本字符输出流
2:基本字符输入流
3:高效字符输出流
和基本字符输出流的写出方式基本一样,只不过注意构造方法
BufferedWriter bw = new BufferedWriter(new FileWriter("c.txt"));

4:高效字符输入流
和基本字符输入流的读取方式基本一样,只不过注意构造方法
BufferedReader br = new BufferedReader(new FileReader("c.txt"));

5:高效字符流的特殊复制文本文件方式
br.readLine(): 读的到换行符吗? 读不到
bw.newLine();

注意细节:
1):高效流的由来?也就是为什么有了高效流
基本字符输入流读入数据的时候,我们开始自己定义数组,给出缓冲区大小,是为了提高效率。
那么,java在设计类的时候,它也考虑到了这一点,所以,就提供了一种高效的流。带缓冲区的流。

2):高效流的构造方法 BufferedWriter(Writer out) 为什么传递的是Writer呢?
因为BufferedWriter这种流,被称为缓冲流,它只提供数据的缓冲功能。
真正的读写还得靠别人。所以,我们这里将使用FileWriter作为参数传递。
缓冲区只提供缓冲功能,没有真正的读写。
3);br.readLine(): 读的到换行符吗? 读不到, 所以说在复制文件的时候 手动加一个bw.newLine();
字节流:
1:基本字节输出流的操作
    
     追加写入用两个参数的构造方法
FileOutputStream fos = new FileOutputStream("a.txt",true);

2:基本字节输入流的操作 FileInputStream
两种方式
一次一个字节
一次一个字节数组
3:高效字节输出流
4:高效字节输入流
注意细节:
1):read():读一个,光标就在下一行等着读下一个,读完后光标就放到了最后,再读就没了
和集合里面迭代器的next() 有点相似

2):当用字节流读汉字并打印到控制台上,有时候会出现 "??" 问题,是因为汉字是由两个字节
组成的,每次读一个字节,所以就会出现"??"的现象,但是此问题用字节流复制文本文件时不会出现

3):不能用字符流复制二进制数据
 二进制流数据:图片,视频,音频等。
 由于二进制的合并为字符,在我们使用的编码表中没有对应的数据,那么,将来在写回去的时候,就会有数据的丢失。
 所以,二进制流数据只能使用字节流进行操作。

举例:  字节 字符

10000 中
10001 国
10002 \u000
10003 你
10004 好
其他内容:

1:复制MP3加入异常处理的标准代码
1)全局变量写在try外面,并且初始化null
BufferedInputStream bis = null;
BufferedOutputStream bos = null;

2)finally里面写close() 注意判断是否为空
finally {

if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2:键盘录入数据写入文本文件
String line = null;
while((line=sc.nextLine())!=null){//"null"
if("over".equals(line)){
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
3:在ArrayList里面存储了3个字符串元素,请把这三个元素写入文本文件。并在每个元素后面加入换行

4:从集合读取数据写入到文件

5:编写复制文件的工具类
注意构造方法私有
所有成员方法公共加静态

6:综合题:将d:\java目录下的所有.java文件复制到d:\jad目录下,并将原来文件的扩展名从.java改为.jad
方式一:先改名再复制
BufferedWriter bw = new BufferedWriter(new FileWriter(newFile));
这里面的 "newFile" 你传入什么名字 那么当你写出这个文件的时候,这个文件就是什么名字

方式二:先复制后改名

[java]  view plain  copy
  1. <span style="white-space:pre">        </span>File[] destFileArray = destFile.listFiles();  
  2.             for(File file : destFileArray){  
  3.                 //file -- d:\\jad\\Hello.java  
  4.                 //结果 -- d:\\jad\\Hello.jad  
  5.                 String name = file.getName(); //Hello.java  
  6.                 String newName = name.replace(".java"".jad");//Hello.jad  
  7.                 File newFile = new File(destFile,newName);//d:\\jad\\Hello.jad  
  8.                 file.renameTo(newFile);  
  9.             }  
四、其他流&编码表、Properties

转换流
1:标准的输入输出流

public static final InputStream in
System.in -- InputStream (字节输出流) 底层是 BufferedInputStream

public static final PrintStream out
System.out -- PrintStream (字节输入流)

注意:必须通过 标准输入流 才能从控制台录入数据
     必须通过 标准输出流 才能把数据写入控制台显示

2.字节输入流转成字符输入流

需求:想自己封装一个键盘录入数据,并存储到文本文件中

问题:如果实现键盘录入数据就必须通过标准输入流
     而标准输入流是字节流,如果用字节流,无法判断每一行的结束
     如果想一行一行的录入,就要用到BufferedReader的readLine方法
     因为BufferedReader需要的是一个字符流,而你现在有的确实一个字节流。
     这就需要字节流转字符流

方法:

字节流通向字符流的桥梁
InputStream -->  InputStreamReader   --> BufferedReader
代码:

[java]  view plain  copy
  1. <span style="white-space:pre">        </span>InputStream is = System.in;  
  2.             InputStreamReader isr = new InputStreamReader(is);  
  3.             BufferedReader br = new BufferedReader(isr);  
  4.             // 封装目的地  
  5.             BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));  
  6.               
  7.             String line = null;  
  8.             while((line=br.readLine())!=null){  
  9.                 //只要是键盘录入,就的自己定义结束条件  
  10.                 if("over".equals(line)){  
  11.                     break;  
  12.                 }  
  13.                 bw.write(line);  
  14.                 bw.newLine();  
  15.                 bw.flush();  
  16.             }  
  17.               
  18.             bw.close();  
  19.             br.close();  
理解:字符流读写数据的底层其实还是调用的字节流,只不过把字节流按照编码顺序排成了字符,从而读出来的是字符
     所以说既然底层调用的是字节流,那么字节流通过InputStreamReader就可以转成字符流,(其实就是把字节加入了一些编码顺序)
     所以说 万流之根源乃字节流,根源演变成了其他流,所以说 字节流可以转字符流,而反过来就不可以

3:字节输出流转字符输出流

需求:把文本文件的数据通过标准输出流的方式显示在控制台。

问题:如果显示到控制台就必须使用 标准输出流,而标准输出流是字节输出流
     这个时候,往控制台写数据的时候,我们又的方式一次写一个字节,或者一次写一个字节数组。
     但是,我们获取到的确实一个字符串数据。
     所以,我们就想能不能直接写一个字符串在控制台呢?
     使用字符缓冲流写出一个字符串。
     所以就需要把字节输出流转成字符输出流

方法:
OutputStream  -- >  OutputStreamWriter   -->  BufferedWriter

代码:
[java]  view plain  copy
  1.    // 封装数据源  
  2. BufferedReader br = new BufferedReader(new FileReader("bw.txt"));  
  3. // 封装目的地  
  4. OutputStream os = System.out;  
  5. OutputStreamWriter osw = new OutputStreamWriter(os);  
  6. BufferedWriter bw  = new BufferedWriter(osw);  
  7.   
  8. String line = null;  
  9. while((line=br.readLine())!=null){  
  10.     bw.write(line);  
  11.     bw.newLine();  
  12.     bw.flush();  
  13. }  
  14. System.out.println();  
  15. bw.close();  
  16. br.close();  

理解:这句话 "OutputStreamWriter 是字符流通向字节流的桥梁" 难理解,因为不知道为什么字符流是字节流的桥梁,
     (按字节的流向,字符流读进来文字,按照字符流写入文件,底层还是调用字节流写入文件的,所以是字符流通向字节流的桥梁)
     不用管OutputStreamWriter是谁到谁的桥梁,我就说上面的是字节流转字符流还是字符流转字节流?
     肯定是字节流转字符流,反过来就不可以(万流之根源乃字节流,根源演变成了其他流)

4:编码问题
流的编码问题:
字符流=字节流+编码表

如果你想在IO流中使用指定编码下数据,用转换流。
 
编码问题其实很简单,永远使用同一种编码即可。
 
FileReader
FileInputStream+GBK
FileWriter
FileOutputStream+GBK

//写入的时候用的字符流的UTF-8编码
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
"osw.txt"), "UTF-8");// 指定编码UTF-8
osw.write("中国");
osw.close();

//那么读出的时候如果用字符流 也应该用 UTF-8编码
InputStreamReader isr = new InputStreamReader(new FileInputStream(
"osw.txt"), "UTF-8");
char[] chs = new char[1024];
int len = isr.read(chs);
String str = new String(chs, 0, len);
System.out.println(str);
     
打印流

PrintStream:字节打印流
PrintWriter:字符打印流

打印流特点:
   A:可以写入任意类型的数据。
   B:可以自动刷新。必须先启动,并且是使用println,printf及format方法才有效。
   C:可以直接对文件进行写入。
  哪些流对象是可以直接对文件进行操作的?
  看构造方法,是否有同时接受File和String类型的参数构造。

注意:打印流只有写数据的,没有读取数据的。

构造方法:
   PrintWriter(String fileName) 

PrintWriter的print()可以写任意类型数据:

PrintWriter 自动刷新功能(必须开启了自动刷新 然后还得是调用println,printf及format方法,才能自动刷新)。
PrintWriter pw = new PrintWriter(new FileWriter("d.txt"), true);
PrintWriter的println()能够自动换行。

案例:用打印流复制文本文件
[java]  view plain  copy
  1. <span style="white-space:pre">    </span>// 封装数据源  
  2.         BufferedReader br = new BufferedReader(new FileReader(  
  3.                 "PrintWriterDemo.java"));  
  4.         // 封装目的地  
  5.         PrintWriter pw = new PrintWriter(new FileWriter("Copy.java"), true);  
  6.           
  7.         String line = null;  
  8.         while((line=br.readLine())!=null){  
  9.             pw.println(line);  
  10.         }  
  11.           
  12.         pw.close();  
  13.         br.close();  
注意:
   A:读取文件的时候,如果是文件夹,会出现:FileNotFoundException: test (拒绝访问。)
   B:写文件的时候,如果没有后缀名,它也会自动生成一个文件,而这个种类型的文件通过记事本类型的软件是可以打开的。

序列化流

序列化:把对象按照流一样的方式传输或者存储。
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。
   void writeObject(Object obj)

反序列化:把网络中的流数据或者文件中的流数据还原成对象。
ObjectInputStream:ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化
  Object readObject()

注意问题:
A:如果类的对象想被序列化流操作,请实现序列化接口。
B:看到了类实现了Serializable接口,如果想解决黄色警告线,请点击鼠标。

java.io.NotSerializableException 没有实现序列化接口异常
 
类通过实现 java.io.Serializable 接口以启用其序列化功能。
该接口被称为序列化接口,是一个标记接口。没有任何功能需要实现。
类一旦实现了该接口,那么,该类的对象就可以被序列化流进行操作。

为什么要写一个序列号(理解即可):

对象在被序列化流进行操作的时候,会记录一个序列号值。而这个序列号值跟对象的成员相关。
最开始的时候:
  Person类的对象 p的id是100
 
write写到文件中: id -- 100
  read读取数据:      id -- 100
后来,我们把write方法给注释了,然后修改了Person类,这个类被修改后,成员就发生了改变。
那么,id也就相应的发生改变。
Person类的对象id改为了200
 
  那么,直接读取,文件中的id是100,而我们有的id是200,他们不匹配,所以报错了。
 
那么,在很多情况下,我们的类中的成员可能会发生改变,不可能说每次改变,我都需要把数据重写入一次。
怎么解决这种情况呢?
先写,在读取。没有问题。
先写,后修改了类,在读取,有问题。
很简单,我们想了这样的一个问题:他们之所以出错,就是因为那个id值不匹配,如果我们直接在类中给一个固定的id值。
那么,无论你怎么修改类的成员,这个id值是不变化的,那这样的话,以后的id永远都是一样的。就不会再因为简单的修改出问题。
问题呢?
怎么定义这个id值呢?
private static final long serialVersionUID = 333558257579870816L;

Properties

Properties:是一个表示属性集的集合。可以从流中加载数据或者把数据保存到流中。键和值都是字符串。
        是唯一一个可以和IO流结合使用的集合类。
  
Properties的父亲是Hashtable,所以,我们知道它是一个Map体现的。那么,我们就存储数据并遍历。

Properties作为集合的特殊功能:
1:修改功能  
public Object setProperty(String key,String value)
2:获取功能
public String getProperty(String key)
public String getProperty(String key,String defaultValue)
public Set<String> stringPropertyNames()

System类的一个方法:  public static Properties getProperties():系统属性

Properties作为和IO流结合使用的集合的特殊功能:

public void list(PrintStream out):把集合中的数据按照键值对的形式存储到文本文件中。
public void list(PrintWriter out):把集合中的数据按照键值对的形式存储到文本文件中。

public void load(InputStream inStream):从文本文件中把数据加载到集合中。
public void load(Reader reader):从文本文件中把数据加载到集合中。
注意: 对文本文件是有要求的,要求数据必须是键值对形式。

public void store(OutputStream out,String comments):把集合中的数据保存到文本文件中。
public void store(Writer writer,String comments):把集合中的数据保存到文本文件中。
注意:store和list方法的区别 list的参数值能是PrintWriter或PrintStream
而store的参数是PrintStream或者Writer

案例:请查找文件user.txt中是否有lisi这个键,如果有,则修改其值为50
[java]  view plain  copy
  1. <span style="white-space:pre">        </span>Properties prop = new Properties();  
  2.   
  3.         // 把文本文件的数据加载到集合中  
  4.         FileReader reader = new FileReader("user.txt");  
  5.         prop.load(reader);  
  6.         reader.close();  
  7.         if (prop.containsKey("lisi")) {  
  8.             prop.setProperty("lisi""50");  
  9.         }  
  10.   
  11.         // 把集合中的数据重新保存到文本文件中  
  12.         FileWriter out = new FileWriter("user.txt");  
  13.         prop.store(out, null);  
  14.         out.close();  

综合案例:我有一个学生类,这个类包含一下成员变量:姓名,语文成绩,数学成绩,英语成绩。
 请从键盘录入5个学生信息,然后按照自己定义的格式存储到文本文件中。
 要求被存储的学生按照分数从高到低排序。
[java]  view plain  copy
  1. // 写一个学生类,有4个成员变量。  
  2.     System.out.println("学生信息录入开始");  
  3.     // 定义TreeSet集合  
  4.     TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {  
  5.         @Override  
  6.         public int compare(Student s1, Student s2) {  
  7.             // 主要条件  
  8.             int num = s2.getSum() - s1.getSum();  
  9.             // 分析次要条件  
  10.             // 当总分相同,还得继续比较每一门的分数是否相同  
  11.             int num2 = (num == 0) ? s1.getChinese() - s2.getChinese() : num;  
  12.             int num3 = (num2 == 0) ? s1.getMath() - s2.getMath() : num2;  
  13.             // 当语文,数学,英语成绩都相同的,我们还得继续判断姓名是否相同。  
  14.             int num4 = (num3 == 0) ? s1.getName().compareTo(s2.getName())  
  15.                     : num3;  
  16.             return num4;  
  17.         }  
  18.     });  
  19.   
  20.   
  21.     for (int x = 0; x < 5; x++) {  
  22.         // 用Scanner实现键盘录入。  
  23.         Scanner sc = new Scanner(System.in);  
  24.         // 键盘录入数据  
  25.         System.out.println("请输入第" + (x + 1) + "个学生的姓名:");  
  26.         String name = sc.nextLine();  
  27.         System.out.println("请输入第" + (x + 1) + "个学生的语文成绩:");  
  28.         int chinese = sc.nextInt();  
  29.         System.out.println("请输入第" + (x + 1) + "个学生的数学成绩:");  
  30.         int math = sc.nextInt();  
  31.         System.out.println("请输入第" + (x + 1) + "个学生的英语成绩:");  
  32.         int english = sc.nextInt();  
  33.   
  34.   
  35.         // 把数据封装到学生对象中  
  36.         Student s = new Student();  
  37.         s.setName(name);  
  38.         s.setChinese(chinese);  
  39.         s.setMath(math);  
  40.         s.setEnglish(english);  
  41.   
  42.   
  43.         ts.add(s);  
  44.     }  
  45.   
  46.   
  47.     // 遍历集合,获取到集合中的每一个数据,用输出流写到文本文件。  
  48.     BufferedWriter bw = new BufferedWriter(new FileWriter("students.txt"));  
  49.     bw.write("姓名\t语文\t数学\t英语");  
  50.     bw.newLine();  
  51.     bw.flush();  
  52.   
  53.   
  54.     for (Student s : ts) {  
  55.         StringBuilder sb = new StringBuilder();  
  56.         sb.append(s.getName()).append("\t").append(s.getChinese())  
  57.                 .append("\t").append(s.getMath()).append("\t")  
  58.                 .append(s.getEnglish());  
  59.         bw.write(sb.toString());  
  60.         bw.newLine();  
  61.         bw.flush();  
  62.     }  
  63.   
  64.   
  65.     bw.close();  
  66.     System.out.println("学生信息录入成功");  
发布了58 篇原创文章 · 获赞 4 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/jackron2014/article/details/52276714