黑马程序员-Java基础:IO流

时间:2023-02-16 13:07:46

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——-

File类 + 异常机制 + IO流


一、异常
在代码的编写过程中,往往不能够考虑到程序在运行时可能出现的所有状况,那么为了处理程序在运行期间可能出现的问题,就需要一个错误处理机制使得程序在出现意料之外的运行状况时可以进行恰当的处理。
Java中提供了异常机制来帮助编程人员处理程序运行中可能出现的错误。

1.异常的继承体系:
黑马程序员-Java基础:IO流

说明:
Java中所有的异常类都继承自一个Throwable类,如果Java中提供的异常不足以处理某些实际程序中的问题,则可以通过继承Throwable类来自定义异常。
Java中将程序异常分为三类:
<1>错误(Error)
指在编写代码时出现的非常严重的错误,出现Error无法运行代码,例如语句某位没有分号结束,内存溢出等。
<2>编译期异常(Exception)
所有继承自Exception类的子类,除了RuntimeException及其子类之外,都属于编译期异常,如果编译器检测到代码中存在编译期异常,则必须在程序编译之前进行处理,否则编译无法通过。

注意:Java在编译代码时会对所有编译期异常进行检查,如果发现未被处理的编译期异常,则编译无法通过。

<3>运行时异常(RuntimeException)
运行时异常属于在程序运行过程中可能产生的异常,这种异常往往是由于程序员的疏忽使代码出存在逻辑性错误而导致的,往往可以通过改进代码避免这种异常,例如NullPointerException:空指针异常。
对于运行时异常可以在程序中进行处理,也可以不予以处理。

2.异常的处理
Error和运行时异常我们在编写代码时都不予以处理。
但编译期异常必须要在代码中进行处理,处理的方式有两种:
<1>throws 抛出异常
这种处理方式较为简单,在产生异常的方法声明处通过throws关键字将异常抛出给调用者去处理(main方法的调用者为JVM,因此在main方法上抛出的异常由JVM处理)
格式:

public void method throws (编译期异常,例如IOException) () {}

注:一个方法中可能抛出多个异常,这时可以通过抛出这些异常的父类来代表所有异常。

建议:尽量不要把主方法中的异常抛出给虚拟机去处理;能在程序中处理的异常尽量不要抛出,应用try catch语句处理

<2>try—catch()—finally 语句处理异常
通过try-catch语句自己处理异常,处理方式如下:

try {
可能产生异常的语句;
}
catch(AnyException e) {
处理异常的方式;
一般为打印异常信息:
e.printStackTrace();
}
finally{
//无论是否产生异常,都一定会执行的语句,可以没有finally语句
一般为关闭资源的代码;
}

如果语句可能产生多种异常,可以通过多个catch代码块进行捕获。

<3>throw 抛出异常对象
如果在方法中某些条件下一定会抛出特定的异常,则可以使用throw关键字在方法体内将异常对象抛出

    public void method() {
int a = 10;
int b = 0;
if (b == 0) {
throw new ArithmeticException();
}
else {
System.out.println(a / b);
}

}

二、File类
1.概述
在IO流操作中有大部分是对文件进行操作,而文件又有路径名,文件名,文件类型等属性,因此将文件的属性和功能抽象出来,称为了表示文件的类,即File类。
2.构造方法
通过构造方法创建一个文件:

A:通过文件路径创建:、
File file = new File("e:\\demo\\a.txt");
B:通过文件目录和文件名创建:
File file = new File("e:\\demo","a.txt");
C:通过目录文件对象和文件名创建:
File file = new File("e:\\demo");
File file2 = new File(file,"a.txt");

3.成员方法
创建功能:

boolean creatNewFile() 通过文件对象创建文件
boolean mkdir() 通过文件对象创建单级目录,若初始化的文件路径为多级目录或指定目录存在,则创建失败
boolean mkdirs() 通过文件对象创建多级目录

删除功能:

boolean delete() 删除文件对象对应的文件
boolean deleteOnExit() 在程序结束时删除文件(可用于临时文件)

重命名功能:

boolean renameTo(File dest) 重命名文件,可用于剪切

判断功能:

boolean exists() 判断文件是否存在
boolean isFile() 判断文件对象路径名表示的是否是文件
boolean isDirectory() 判断文件对象路径名表示的是否是目录
boolean isHidden() 判断文件对象是否为隐藏文件
boolean isAbsolute() 判断文件路径名是否为绝对路径
还有其他判断文件权限的功能,在此不一一列举,详细方法查询API文档

获取功能:

String getName() 获取文件名称
String getPath() 获取文件相对路径
String getAbsolutePath() 获取文件绝对路径
String getParent() 获取文件所在目录名称
File getParentFile() 获取文件所在目录的文件对象
还有其他获取文件对象元素的方法,请查阅API文档

高级获取功能:

File[] listFiles() 获取当前目录下所有文件的文件对象
String[] list() 获取当前目录下所有文件的文件名
String[] list(FileNameFilter filter) 通过文件名过滤器获取当前目录下符合过滤规则的文件名
File[] listFiles(FileNameFilter filter) 通过文件名过滤器获取当前目录下符合过滤规则的文件对象

熟悉上面的方法,就可以在IO流中使用文件类对指定的文件进行操作。

三、IO流
1.概述
IO流即输入输出流,用于处理数据的传输。
其中输入和输出都是相对与程序而言的。
Java中用于操作IO流的类都在io包中。

2.IO流的分类

 IO流的分类:
流向:
输入流 读取数据
输出流 写出数据
数据类型:
字节流
字节输入流 读取数据 InputStream
字节输出流 写出数据 OutputStream
字符流
字符输入流 读取数据 Reader
字符输出流 写出数据 Writer

注:由上面四个类派生出的子类都以父类名作为后缀名

1.字节流
<1>读取数据:
InputStream——>FileInputStream : 文件字节输入流
文件字节流输入构造方法

FileInputStream(File file) 通过文件对象创建输入流
FileInuptStream(String name) 通过文件名创建输入流

成员方法

public int read() 一次读取一个字节
public int read(byte[] b) 一次读取一个字节数组
public void close() 释放资源

代码示例

InputStream input = new FileInputStream("input.txt");
//一次读取一个字节
int data = 0;
while((data = input.read()) != -1) {
System.out.println(data);
}
//一次读取一个字节数组
byte[] bytes = new byte[1024];
int len = 0;
while((len = input.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
//释放资源
input.close();

<2>写入数据
OutputStream——>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) 一次写入一个字节数组,指定写入开始位置和写入字节数
public void close() 释放资源
public void flush() 刷新流

代码示例

OutputStream output = new FileOutputStream("output.txt");
//一次写入一个字节
int data = 'A';
output.write(data);
//一次写入一个字节数组
byte[] bytes = {'a', 'b', 'c', 'd'};
output.write(bytes);
//指定写入数组的起始位置和长度
int len = 3;
output.write(bytes, 0, 3);
//释放资源
output.close();

2.字节缓冲流
为了提高字节流的输入输出效率,Java提供了缓冲流,缓冲流是指将字节流进行包装,为字节流传输的数据提供缓冲区,类似于电脑的内存机制。
BufferedInputStream,BufferedOutputStream
构造方法

BufferedInputStream(InputStream in) 通过字节输入流构造一个缓冲流
BufferedOutputStream(OutputStream out) 通过字节输出流构造一个缓冲流

通过字节缓冲流复制文件

BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("inputFile.mp3"));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("outputFile.mp3"));
//一次复制一个字节
int data = 0;
while((data = bis.read()) != -1) {
bos.write(data);
}
//一次复制一个字节数组
byte[] bytes = new byte[1024];
int len;
while((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
//关闭资源
bis.close();
bos.close();

3.转换流
由于字节流操作纯文本类型的文件不方便,因为世界上有不同的语言,每一种语言对应的字符集都不相同,因此提供了转换流,将字节转换为字符。
字符流 = 字节流 + 编码表
编码表:由字符及其对应的数值组成的一张表
常见编码表:
ASCII/Unicode 字符集
ISO-8859-1
GB2312/GBK/GB18030
BIG5
UTF-8

<1>字节转换为字符—转换输入流
InputStreamReader
构造方法:

public InputStreamReader(InputStream in) 将字节输入流转换为字符流,使用默认编码表GBK
public InputStreamReader(InputStream in, String charsetName)
字节输入流转换为字符流,并指定编码表

成员方法:

public int read() 一次读取一个字符
public int read(char[] cbuf, int off, int len) 一次读取一个字符数组
String getEncoding() 获取当前流所用的编码表、
public void close() 关闭资源

<2>字符转换为字节—转换输出流
OutputStreamWriter
构造方法:

public OutputStreamWriter(OutputStream out)
public OutputStreamWriter(OutputStream out, String charsetName)

成员方法:

void write(int c)
void write(char[] cbuf, int off, int len)
void write(String str, int off, int len)一次写入一个字符串,指定字符串的开始位置和长度

<3>转换流复制文件案例

//创建转换输入输出流,并指定编码表
//注意:输入输出编码表要一致,不然会出现乱码问题
InputStreamReader isr = new InputStreamReader(
new FileInputStream("input.txt"), "GBK");
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("output.txt"), "GBK");
//一次转换一个字符
int c = 0;
while((c = isr.read()) != -1) {
osw.write(c);
}
//一次转换一个字符数组
char[] chars = new char[1024];
int len;
while((len = isr.read(chars)) != -1) {
osw.write(chars, 0, len);
//一次转换一个字符串
//osw.write(new String(chars), 0, len);
}

4.字符流
字符流的存在只是为了方便表示实际中的语言字符,而计算机底层数据的传递都使用字节流,因此任何字符流在计算机中实际都是以字节流表示。
<1>Reader
文件字符输入流:FileReader
文件字符流继承自转换流,没有特有的方法
<2>Writer
文件字符输出流:FileWriter
<3>字符流复制文件

Reader reader = new FileReader("read.txt");
Writer writer = new FileWriter("write.txt");
//一个字符
int c = 0;
while((c = reader.read()) != -1) {
writer.write(c);
}
//一次转换一个字符数组
char[] chars = new char[1024];
int len;
while((len = reader.read(chars)) != -1) {
writer.write(chars, 0, len);
//一次转换一个字符串
//writer.write(new String(chars));
}
//关闭资源
reader.close();
writer.close();

5.字符缓冲流
BufferedReader , BufferedWriter
在字符流上加入缓冲区,提高字符流输入输出的效率。
字符缓冲流特有的复制文本文件的方式

BufferedReader in = new BufferedReader(
new FileReader("in.txt"));
BufferedWriter out = new BufferedWriter(
new FileWriter("out.txt"));
//一次读取一行字符
String line = null;
while((line = in.readLine()) != null) {
out.write(line);
out.newLine();
out.flush();
}
//关闭资源
in.close();
out.close();

6.IO流体系小结

IO流
|--字节流
|--字节输入流
InputStream
int read():一次读取一个字节
int read(byte[] bys):一次读取一个字节数组

|--FileInputStream
|--BufferedInputStream
|--字节输出流
OutputStream
void write(int by):一次写一个字节
void write(byte[] bys,int index,int len):一次写一个字节数组的一部分

|--FileOutputStream
|--BufferedOutputStream
|--字符流
|--字符输入流
Reader
int read():一次读取一个字符
int read(char[] chs):一次读取一个字符数组

|--InputStreamReader
|--FileReader
|--BufferedReader
String readLine():一次读取一个字符串
|--字符输出流
Writer
void write(int ch):一次写一个字符
void write(char[] chs,int index,int len):一次写一个字符数组的一部分

|--OutputStreamWriter
|--FileWriter
|--BufferedWriter
void newLine():写一个换行符

void write(String line):一次写一个字符串