第四部分 I/O与异常

4.1 I/O

I/O的核心组成为5个类(File、OutputStream、InputStream、Reader、Writer)和一个接口(Serializable)

4.1.1  File

1、创建文件类:File file = new File(path);或者File file = new File(path,subpath);

2、相关方法:

创建文件

public boolean createNewFile() throws IOException

判断文件是否存在

public boolean exists()

删除文件

public boolean delete()

取得父路径或父File对象

public String getParent()

创建目录

public boolean mkdirs()

判断路径是否是文件:

public boolean isFile()

判断路径是否是目录

public boolean isDirectory()

取得文件大小(字节)

public long length()

最后一次修改日期

public long lastModified()

3、相关参数:

文件路径分隔符:File.separator

 

import java.io.File;

public class TestIO {

    public static void main(String[] args) {

        File file = new File(File.separator + "Users" + File.separator + "yuisama" +

File.separator + "Desktop") ;

        listAllFiles(file) ; // 从此处开始递归

    }

    public static void listAllFiles(File file) {

        if (file.isDirectory()) { // 现在给定的file对象属于目录

            File[] result = file.listFiles() ; // 继续列出子目录内容

            if (result != null) {

                for (File file2 : result) {

                    listAllFiles(file2) ;

                }

            }

        }else {

            // 给定的file是文件,直接打印

            System.out.println(file) ;

        }

    }

}

 

4.1.2 字符流和字节流

字节流:InputStream、OutputStream

字符流:Reader、Writer

字节流是原生的操作,而字符流是经过处理后的操作。

程序字节输出流OutputStream

如果要想通过程序进行内容输出,则可以使用java.io.OutputStream。

import java.io.File;

import java.io.FileOutputStream;

import java.io.OutputStream;

 

public class TestIO {

    public static void main(String[] args) throws Exception{

        File file = new File(File.separator + "Users" + File.separator + "yuisama" +

File.separator + "Desktop"

                + File.separator + "hello.txt");

        if (!file.getParentFile().exists()) { // 必须保证父目录存在

            file.getParentFile().mkdirs() ; // 创建多级父目录

        }

        // OutputStream是一个抽象类,所以需要通过子类进行实例化,此时只能操作File类

        OutputStream output = new FileOutputStream(file) ;

        // 要求输出到文件的内容

        String msg = "test.txt" ;  

        // 将内容变为字节数组

        output.write(msg.getBytes());

        // 关闭输出

        output.close();

    }

}

字节输入流InputStream

 

import java.io.File;

import java.io.FileInputStream;

import java.io.InputStream;

 

public class TestInputStream {

 

    public static void main(String[] args) throws Exception {

        // 1.定义文件路径

        File file = new File(File.separator + "Users" + File.separator + "yuisama" +

File.separator + "Desktop"

                + File.separator + "hello.txt");

        // 2.必须保证文件存在才能进行处理

        if (file.exists()) {

            InputStream input = new FileInputStream(file) ;

            byte[] data = new byte[1024] ; // 每次可以读取的最大数量

            int len = input.read(data) ; // 此时的数据读取到了数组之中

            String result = new String(data,0,len) ; // 将字节数组转为String

            System.out.println("读取内容【"+result+"】") ;

            input.close();

        }

    }

 

}

字符输入流Writer

import java.io.File;

import java.io.FileWriter;

import java.io.Writer;

 

public class TestWriter {

 

    public static void main(String[] args) throws Exception {

        File file = new File(File.separator + "Users" + File.separator + "yuisama" +

File.separator + "Desktop"

                + File.separator + "hello.txt");

        if (!file.getParentFile().exists()) { // 必须保证父目录存在

            file.getParentFile().mkdirs() ; // 创建多级父目录

        }

        String msg = "比特科技java公开课" ;

        Writer out = new FileWriter(file) ;

        out.write(msg) ;

        out.close() ;

    }

 

}

 

字符输入流Reader

import java.io.File;

import java.io.FileReader;

import java.io.Reader;

 

public class TestReader {

 

    public static void main(String[] args) throws Exception{

        // 1.定义文件路径

        File file = new File(File.separator + "Users" + File.separator + "yuisama" +

File.separator + "Desktop"

                + File.separator + "hello.txt");

        // 2.必须保证文件存在才能进行处理

        if (file.exists()) {

            Reader in = new FileReader(file) ;

            char[] data = new char[1024] ;

            int len = in.read(data) ; // 将数据读取到字符数组中

            String result = new String(data, 0, len) ;

            System.out.println("读取内容【"+result+"】") ;

            in.close();

        }

    }

}

 

下面哪段程序能够正确的实现了GBK编码字节流到UTF-8编码字节流的转换:

byte[] src,dst;

 

 

正确答案: B   

dst=String.frombytes(src,”GBK”).getbytes(“UTF-8”)

dst=new String (src,”GBK”).getbytes(“UTF-8”)

dst=new String (”GBK”, src,) getbytes()

dst=String.encode(String.decode(src,”GBK”)), “UTF-8”)

 

 

4.1.3 内存流

在之前所有的操作都是针对于文件进行的IO处理。除了文件之外,IO的操作也可以发生在内存之中,这种流称之为内存操作流。文件流的操作里面一定会产生一个文件数据(不管最后这个文件数据是否被保留)。如果现在需要进行IO处理,但是又不希望产生文件。这种情况下就可以使用内存作为操作终端。

对于内存流也分为两类:

1. 字节内存流:ByteArrayInputStream、ByteArrayOutputStream

2. 字符内存流:CharArrayReader、CharArrayWriter

4.1.4 打印流

打印流解决的就是OutputStream的设计缺陷,属于OutputStream功能的加强版。如果操作的不是二进制数据,只是想通过程序向终端目标输出信息的话,OutputStream不是很方便,其缺点有两个:

1. 所有的数据必须转换为字节数组。

2. 如果要输出的是int、double等类型就不方便了

打印流设计的主要目的是为了解决OutputStream的设计问题,其本质不会脱离OutputStream。

4.1.5 序列化

序列化基本概念

对象序列化指的是:将内存中保存的对象变为二进制数据流的形式进行传输,或者是将其保存在文本中。但是并不意味着所有类的对象都可以被序列化,严格来讲,需要被序列化的类对象往往需要传输使用,同时这个类必须实现java.io.Serializable接口。但是这个接口并没有任何的方法定义,只是一个标识而已。

 

4.2异常

几乎所有的代码里面都会出现异常,为了保证程序在出现异常之后可以正常执行完毕,就需要进行异常处理。所有的异常都是由Throwable继承而来,而它的两个子类为Error和Exception。

第四部分 I/O与异常

Error指的是错误,一般是Java运行时的内部错误和资源耗尽错误。一旦出现则直接终止程序。Exception是异常,异常又分为IOException(IO出现错误)和RuntimeException(程序出现错误)。如果出现了异常但是没有合理处理的话就会导致程序中止执行。

Java语言规范将派生于Error类或RuntimeException类的所有异常称为非受查异常;所有的其他异常称为受查异常。

public class Test {

    public static void main(String[] args) {

        System.out.println("1.数学计算开始前");

        System.out.println("2.进行数学计算:"+10/0);

        System.out.println("3.数学计算结束后");

    }

}

 

4.2.1 异常处理

异常处理的语法格式如下:

try{   

    有可能出现异常的语句 ;

}[catch (异常类 对象) {

} ... ]

[finally {

    异常的出口

}]

 

 

public class Test {

    public static void main(String[] args) {

        System.out.println("1.数学计算开始前");

        try {

            System.out.println("2.进行数学计算:"+10/0);

        } catch (ArithmeticException e) {

            e.printStackTrace();

        }

        System.out.println("3.数学计算结束后");

    }

}

 

关于try……catch……finally结构的几点说明:

1、try必须要有,catch和finally可以根据需要选择catch或者finally或者两者同时使用;

2、如果需要捕获多个异常,可以使用多个catch语句,但每个catch语句块只能捕获一个异常;

3、catch只有在捕获到异常的时候才会执行,而finally作为这个程序块的统一出口,无论程序是否发生异常,finally块内的语句都一定会执行;

4、如果catch语句块中出现了return语句,要先执行finally语句块的内容之后再执行return语句。但是如果finally使用了return或者throw语句,将会使try……catch中的return或者throw失效。

 

4.2.2 throws关键字

为了说明方法中可能产生的异常,可以使用throws进行声明,此外表示这个方法出现问题后不希望进行处理,就是用throws抛出。此时如果有其他方法调用这个方法就必须使用try/catch进行捕获。

当抛出异常的方法是主方法时,一旦产生了异常就会交给JVM进行处理。

4.2.3 throw关键字

throw直接编写在语句中,表示人为的抛出异常。如果现在异常类对象实例化不希望由JVM产生而由用户产生,就可以使用throw完成。

 

如下代码的输出是

package Test;

public class Test {

    private static void test(int[] arr) {

        for (int i = 0; i < arr.length; i++) {

            try {

                if (arr[i] % 2 == 0) {

                    throw new NullPointerException();

                } else {

                    System.out.print(i);

                }

            } finally {

                System.out.print("e");

            }

        }

    }

 

    public static void main(String[]args) {

        try {

            test(new int[] {0, 1, 2, 3, 4, 5});

        } catch (Exception e) {

            System.out.print("E");

        }

    }

 

}

 

正确答案: B  

编译出错

eE

Ee

eE1eE3eE5

Ee1Ee3Ee5

 

4.2.4 RuntimeException

这类异常即便没有异常处理也可以正常执行。很多的代码上都可能出现异常,例如"10/0"都可能产生异常,如果所有可能产生异常的地方都强制性异常处理,这个代码就太复杂了。所以在异常设计的时候,考虑到一些异常可能是简单问题,所以将这类异常称为RuntimeException,也就是使用RuntimeException定义的异常类可以不需要强制性进行异常处理。

请解释Exception与RuntimeException的区别,请列举几个常见的RuntimeException:

1. 使用Exception是RuntimeException的父类,使用Exception定义的异常都要求必须使用异常处理,而使用RuntimeException定义的异常可以由用户选择性的来进行异常处理。

2. 常见的RuntimeException:ClassCastException、NullPointerException等。

4.2.5 assert

1、assert的语法:assert 表达式;

2、只有assert后的表达式为真时才能继续执行,否则直接中断。

3、要使用断言,则需要在编译的时候输入 –ea参数启用断言。

4、Java为了与C++兼容所以引入断言机制,实际不推荐使用。

public class Test {

    public static void main(String[] args){

        int num = 10 ;

        assert num == 55 : "错误:num应当为55" ;

        System.out.println(num);

    }

}