1. IO流的概念和应用场景
1.1 什么是流?
流, 本身是一个非常抽象的概念, 以现实生活中水为例, 我们通过管道把A池子的水放到B池子中这个过程就会产生水流, 而主体是水.
1.2 什么是IO流?
IO流 -- 输入(Input)输出(Output)流
IO流可以看做不同储存设备之间的数据交换产生的 数据流
根据流向分类:
输入流: 把数据从其他设备上读取到内存中的流
输出流: 把数据存内存中写出到其他设备上的流
根据数据类型分类:
字节流: 以字节为单位读写数据的流
字符流: 以字符为单位读写数据的流
1.3 为什么需要IO流
实际开发中使用较多, 包括文件上传下载, 文件读写等等都会用到IO流
例如:
一个简单的记事本的打开保存功能
程序后台把错误日志数据保存到磁盘文件中
1.4 字节流
一切文件数据在储存时, 都是以二进制数字的形式保存, 传输时也是如此. 所以, [字节流可以传输任意文件数据].
1.4.1 字节输出流常用API
void close ()
:关闭此输出流并释放与此流相关的任何系统资源
void flush ()
:刷新此输出流并强制任何缓冲的输出字节被写出
void write (byte[] b)
:将b.length个数的字节从指定的字节数组写入此输出流
void write (byte[] b, int off, int len)
:将指定的数组从指定下标off开始写入len个个数的字节到此输出流
数据追加续写:
public FileOutputStream(String name, boolean append)
:创建文件输出流以指定的名称写入文件
1.4.2 字节输入流常用API
void close ()
:关闭此输入流并释放与此流相关的任何系统资源
int read(byte[] b)
:从输入流中读取一些字节数,并将它们存储到字节数组 b中
1.5 字符流
当使用字节流读取文本文件时,可能会有一个小问题
就是遇到中文字符时,可能不会显示完整的字符,那是因为一个中文字符可能占用多个字节存储
所以Java提供一些字符流类,以字符为单位读写数据,专门用于处理文本文件。
1.5.1 字符输入流常用API
void close()
:关闭此流并释放与此流相关联的任何系统资源。
int read()
:从输入流读取一个字符。
int read(char[] ch)
:从输入流中读取一些字符,并将它们存储到字符数组 ch中
1.5.2 字符输出流常用API
write(int c)
: 写入单个字符
write(char[] ch)
: 写入字符数组
void write(char[] ch, int off, int len)
: 写入字符数组的某一部分,off数组的开始索引,len写的字符个数
void write(String str)
: 写入字符串
void write(String str, int off, int len)
: 写入字符串的某一部分,off字符串的开始索引,len写的字符个数
void flush()
: 刷新该流的缓冲
void close()
: 关闭此流,但要先刷新它
1.6 缓冲流
缓冲流,也叫高效流,是对4个基本的FileXxx 流的增强,所以也是4个流,按照数据类型分类:
1. 字节缓冲流:
BufferedInputStream, BufferedOutputStream
2. 字符缓冲流:
BufferedReader, BufferedWriter
public class BufferedDemo {
public static void main(String[] args) throws FileNotFoundException {
long start = System.currentTimeMillis();
try (
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("JDK8.zip"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.zip"));
){
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
} catch (IOException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");
}
}
1.7 转换流
什么是转换流?
在IDEA中,使用FileReader 读取项目中的文本文件
由于IDEA的设置,都是默认的UTF-8编码,所以没有任何问题
但是,当读取Windows系统中创建的文本文件时,由于Windows系统的默认是GBK编码,就会出现乱码
这时, 就需要用转换流进行编码集转换
1.7.1 InputStreamReader
转换流java.io.InputStreamReader,是Reader的子类,是从字节流到字符流的桥梁
它读取字节,并使用指定的字符集将其解码为字符。它的字符集可以由名称指定,也可以接受平台的默认字符集
public class ReaderDemo2 {
public static void main(String[] args) throws IOException {
String FileName = "E:\\file_gbk.txt";
InputStreamReader isr = new InputStreamReader(new FileInputStream(FileName));
InputStreamReader isr2 = new InputStreamReader(new FileInputStream(FileName) , "GBK");
int read;
while ((read = isr.read()) != -1) {
System.out.print((char)read);
}
isr.close();
while ((read = isr2.read()) != -1) {
System.out.print((char)read);
}
isr2.close();
}
}
1.7.2 OutputStreamWriter
转换流java.io.OutputStreamWriter ,是Writer的子类,是从字符流到字节流的桥梁
使用指定的字符集将字符编码为字节。它的字符集可以由名称指定,也可以接受平台的默认字符集。
public class OutputDemo {
public static void main(String[] args) throws IOException {
String FileName = "E:\\out.txt";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(FileName));
osw.write("你好");
osw.close();
String FileName2 = "E:\\out2.txt";
OutputStreamWriter osw2 = new OutputStreamWriter(new FileOutputStream(FileName2),"GBK");
osw2.write("你好");
osw2.close();
}
}
1.7.3 代码演示
public class TransDemo {
public static void main(String[] args) {
String srcFile = "file_gbk.txt";
String destFile = "file_utf8.txt";
InputStreamReader isr = new InputStreamReader(new FileInputStream(srcFile) , "GBK");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(destFile));
char[] cbuf = new char[1024];
int len;
while ((len = isr.read(cbuf))!=-1) {
osw.write(cbuf,0,len);
}
osw.close();
isr.close();
}
}
2. 递归
2.1 递归概述
递归:
指在当前方法内调用自己的这种现象
递归的分类:
直接递归:
方法自身调用自己的方式叫做直接递归
间接递归:
A方法调用B方法, B方法调用C方法, C方法调用A方法的方式就叫做间接递归
注意事项:
1. 递归一定要有条件限定, 以保证递归能够停止, 否则会发生栈内存溢出
2. 虽然有条件限定, 但是递归次数不能太多, 否则也会发生栈内存溢出
3. 构造方法禁止递归
2.2 代码演示:
public class Demo1 {
public static void main(String[] args) {
b(1);
}
public Demo01DiGui() {
}
private static void b(int i) {
System.out.println(i);
if(i==5000){
return;
}
b(++i);
}
private static void a() {
System.out.println("a方法");
a();
}
}
**计算1 ~ n的和**
**分析**:num的累和 = num + (num-1)的累和,所以可以把累和的操作定义成一个方法,递归调用
public class Demo2 {
public static void main(String[] args) {
int num = 5;
int sum = getSum(num);
System.out.println(sum);
}
public static int getSum(int num) {
if(num == 1){
return 1;
}
return num + getSum(num-1);
}
}
搜索`D:\aaa` 目录中的`.java` 文件。
**分析**:
1. 目录搜索,无法判断多少级目录,所以使用递归,遍历所有目录。
2. 遍历目录时,获取的子文件,通过文件名称,判断是否符合条件。
public class Demo3 {
public static void main(String[] args) {
File dir = new File("D:\\aaa");
printDir(dir);
}
public static void printDir(File dir) {
File[] files = dir.listFiles();
for (File file : files) {
if (file.isFile()) {
if (file.getName().endsWith(".java")) {
System.out.println("文件名:" + file.getAbsolutePath());
}
} else {
printDir(file);
}
}
}
}