异常概述
讲解IO流之前为什么先讲解异常和File类呢?
因为File表示的是IO流将来要操作的文件,所以我们需要学习File类。
而操作文件无非就是上传文件和下载文件,在这个操作的过程中可能出现问题,
出现问题后,我们需要对对应的代码进行处理。所以我们需要学习异常异常。
- 异常:异常就是Java程序在运行过程中出现的错误。
- 异常由来:问题也是现实生活中一个具体事务,也可以通过java
的类的形式进行描述,并封装成对象。其实就是Java对不正常情况进行描述后的对象体现。 - 我们见过的异常,角标越界异常,空指针异常
异常分类
1,编译时异常
除了RuntimeException及其子类,Exception中所有的子类都是,这种异常必须要处理,要不编译通不过
2,运行是异常
RuntimeException及其子类都是,这种异常不用处理,编译会通过,不过这样的程序会有安全隐患,遇到这种异常是需要改代码的
3,严重错误问题
用Error进行描述,这个问题发生后,一般不编写针对代码进行处理,而是要对程序进行修正.通常都是由虚拟机抛出的问题
JVM的默认处理方案
- 把异常的名称,错误原因及异常出现的位置等信息输出在了控制台
- 程序停止执行
jvm发现运算是已经违反了数学运算规则,java将这种常见的问题进行描述,并封装成了对象叫做ArithmeticException
当除0运算发生后,jvm将该问题打包成了一个异常对象.
并将对象抛给调用者main函数,new ArithmeticException(“/by zero”);
main函数收到这个问题时,有两种处理方式:
1,自己将该问题处理,然后继续运行
2,自己没有针对的处理方式,只有交给调用main的jvm来处理
jvm有一个默认的异常处理机制,就将该异常进行处理.并将该异常的名称,异常的信息.异常出现的位置打印在了控制台上
同时将程序停止运行
异常处理方案
异常处理方案
try…catch…finally
throws
编译时异常和运行时异常的区别
Java中的异常被分为两大类:编译时异常和运行时异常。所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常
编译时异常
Java程序必须显示处理,否则程序就会发生错误,无法通过编译
运行时异常
无需显示处理,也可以和编译时异常一样处理
Throwable中的方法
getMessage()
获取异常信息,返回字符串。
toString()
获取异常类名和异常信息,返回字符串。
printStackTrace()
获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
printStackTrace(PrintStream s)
通常用该方法将异常内容保存在日志文件中,以便查阅。
throws
定义功能方法时,需要把出现的问题暴露出来让调用者去处理。那么就通过throws在方法上标识。
throw
在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
throws和throw的区别
throws
用在方法声明后面,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,并不一定会发生这些异常throw
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
throw则是抛出了异常,执行throw则一定抛出了某种异常
我们到底该如何处理异常呢
- 原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
区别:
后续程序需要继续运行就try
后续程序不需要继续运行就throws举例:
感冒了就自己吃点药就好了,try
吃了好几天药都没好结果得了H7N9,那就的得throws到医院
如果医院没有特效药就变成Error了
finally的特点作用及面试题
finally的特点
被finally控制的语句体一定会执行
特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))finally的作用
用于释放资源,在IO流操作和数据库操作中会见到
finally相关的面试题
final,finally和finalize的区别
如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。
自定义异常
自定义异常
继承自Exception
继承自RuntimeException
异常注意事项
子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
File类概述和构造方法
File类的概述
文件和目录路径名的抽象表示形式
构造方法
public File(String pathname) public File(String parent,String child) public File(File parent,String child)
File类的成员方法
创建功能
public boolean createNewFile() public boolean mkdir() public boolean mkdirs()
删除功能
public boolean delete()
重命名功能
public boolean renameTo(File dest)
判断功能
public boolean isDirectory() public boolean isFile() public boolean exists() public boolean canRead() public boolean canWrite() public boolean isHidden()
基本获取功能
public String getAbsolutePath() public String getPath() public String getName() public long length() public long lastModified()
高级获取功能
public String[] list() public File[] listFiles()
IO流概述
IO流用来处理设备之间的数据传输
上传文件和下载文件
Java对数据的操作是通过流的方式
- Java用于操作流的对象都在IO包中
IO流分类
按照数据流向
输入流 读入数据
输出流 写出数据按照数据类型
字节流
字符流什么情况下使用哪种流呢?
如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流。其他用字节流。
如果你什么都不知道,就用字节流
IO流常用基类
字节流的抽象基类:
InputStream ,OutputStream。
字符流的抽象基类:
Reader , Writer。
注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
如:InputStream的子类FileInputStream。
如:Reader的子类FileReader。
字节流写数据
OutputStream
FileOutputStream
往一个文本文件中写一句话:”helloworld”
分析发现其实更适合用字符流,但是由于字节流先出现,所以,我们考虑先使用字节流后面再讲会什么出现字符流。
FileOutputStream的构造方法
FileOutputStream(File file)
FileOutputStream(String name)
字节流写数据的方式
public void write(int b)
public void write(byte[] b)
public void write(byte[] b,int off,int len)
字节流读取数据
InputStream
FileInputStream
FileInputStream的构造方法
FileInputStream(File file)
FileInputStream(String name)FileInputStream的成员方法
public int read()
public int read(byte[] b)
字节流读取数据两种方式
一次读取一个字节
一次读取一个字节数组
字节缓冲流
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式),所以提供了字节缓冲区流
字节缓冲输出流
BufferedOutputStream
字节缓冲输入流
BufferedInputStream
转换流出现的原因及思想
由于字节流操作中文不是特别方便,所以,java就提供了转换流。
字符流=字节流+编码表。
编码表概述和常见的编码表
编码表
由字符及其对应的数值组成的一张表
常见编码表
ASCII/Unicode 字符集
ISO-8859-1
GB2312/GBK/GB18030
BIG5
UTF-8
字符串中的编码问题
编码
把看得懂的变成看不懂的
解码
把看不懂的变成看得懂的
转换流概述
- OutputStreamWriter 字符输出流
public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out,String charsetName)
- InputStreamReader 字符输入流
public InputStreamReader(InputStream in)
public InputStreamReader(InputStream in,String charsetName)
OutputStreamWriter写数据
- OutputStreamWriter写数据方法
public void write(int c)
public void write(char[] cbuf)
public void write(char[] cbuf,int off,int len)
public void write(String str)
public void write(String str,int off,int len)
字符流操作要注意的问题
flush()的作用
flush()和close()的区别
InputStreamReader读数据
- InputStreamReader读数据方法
public int read()
public int read(char[] cbuf)
转换流的简化写法
- 转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。
- FileWriter
- FileReader
FileWriter和FileReader
- FileWriter写数据
- FileReader读取数据
- FileWriter和FileReader实现文本文件的复制
字符缓冲流
- BufferedWriter基本用法
- BufferedReader基本用法
- 字符缓冲流复制文本文件
特殊功能
BufferedWriter
void newLine()
BufferedReader
String readLine()字符缓冲流特殊功能复制文本文件
IO流小结
字节流
字节输入流
字节输出流字符流
字符输入流
字符输出流
操作基本数据类型的流
操作基本数据类型
DataInputStream
DataOutputStream
1:数据输出流允许应用程序以适当方式将基本 Java 数据类型写入输出流中。然后,应用程序可以使用数据输入流将数据读入。
2:案例
public static void main(String[] args) throws IOException {
write();
read();
}
private static void read() throws FileNotFoundException, IOException {
DataInputStream dis = new DataInputStream(
new FileInputStream("dos.txt"));
byte b = dis.readByte();
System.out.println(b);
short s = dis.readShort();
System.out.println(s);
int i = dis.readInt();
System.out.println(i);
long l = dis.readLong();
System.out.println(l);
float f = dis.readFloat();
System.out.println(f);
double d = dis.readDouble();
System.out.println(d);
char ch = dis.readChar();
System.out.println(ch);
boolean bb = dis.readBoolean();
System.out.println(bb);
dis.close();
}
private static void write() throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream(
"dos.txt"));
dos.writeByte(1);
dos.writeShort(20);
dos.writeInt(300);
dos.writeLong(4000);
dos.writeFloat(12.34f);
dos.writeDouble(12.56);
dos.writeChar('a');
dos.writeBoolean(true);
dos.close();
}
内存操作流
操作字节数组
ByteArrayInputStream
ByteArrayOutputStream操作字符数组
CharArrayReader
CharArrayWrite操作字符串
StringReader
StringWriter
1:内存操作流一般用于处理临时信息,因为临时信息不需要保存,使用后就可以删除。
2:以第一个举例即可
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write("helloworld".getBytes());
baos.close();
byte[] bys = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bys);
int by = 0;
while ((by = bais.read()) != -1) {
System.out.println((char) by);
}
baos.close();
bais.close();
最后的close()可以不写,通过看源码可以知道这里什么都没有做。
打印流
打印流概述
字节流打印流
字符打印流打印流特点
只能操作目的地,不能操作数据。
可以操作任意类型的数据。
如果启动了自动刷新,能够自动刷新。
可以操作文件的流打印流复制文本文件
标准输入输出流
- System类中的字段:in,out。
- 它们各代表了系统标准的输入和输出设备。
- 默认输入设备是键盘,输出设备是显示器。
- System.in的类型是InputStream.
System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.
随机访问流
RandomAccessFile概述
RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。
1:访问模式
"r" 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
"rws" 打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
"rwd" 打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。
一般使用rw模式。
2:案例
public static void main(String[] args) throws IOException {
write();
read();
}
private static void read() throws IOException {
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");
int i = raf.readInt();
System.out.println(i);
System.out.println("当前指针位置:" + raf.getFilePointer());
char ch = raf.readChar();
System.out.println(ch);
System.out.println("当前指针位置:" + raf.getFilePointer());
String s = raf.readUTF();
System.out.println(s);
System.out.println("当前指针位置:" + raf.getFilePointer());
System.out.println("读取数据完毕");
System.out.println("当前指针位置:" + raf.getFilePointer());
raf.seek(0);// 返回数据开头
int ii = raf.readInt();
System.out.println(ii);
}
private static void write() throws IOException {
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");
raf.writeInt(100); // 写入int类型
raf.writeChar('爱');// 写入字符
raf.writeUTF("中国你好");// 写入字符串
raf.close();
System.out.println("写入成功");
}
合并流
SequenceInputStream概述
SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。
SequenceInputStream的构造方法
SequenceInputStream(InputStream s1, InputStream s2)
SequenceInputStream(Enumeration<? extends InputStream> e)
把多个文件的内容写入到一个文本文件
序列化流
对象序列化是将对象状态转换为可保持或传输的过程。一般的格式是与平台无关的二进制流,可以将这种二进制流持久保存在磁盘上,也可以通过网络将这种二进制流传输到另一个网络结点。
对象反序列化,是指把这种二进制流数据还原成对象。
序列化流
ObjectOutputStream
反序列化流
ObjectInputStream
Properties集合
Properties概述
Properties作为Map集合的使用
Properties的特殊功能
public Object setProperty(String key,String value)
public String getProperty(String key)
public Set<String> stringPropertyNames()
- Properties和IO流的结合使用
public void load(Reader reader)
public void store(Writer writer,String comments)