第四部分 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。
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); } } |