前置知识: File 类的基本使用与了解。
流:
在介绍 IO 流之前先来说下什么是流: 流是一种 FIFO 的数据结构(类似于队列,先进先出)。简单来说,就像水流一样。
输入流和输出流:
输入流和输出流是相对于 内存 这个参照物来说的。
流的划分:
上图中很多类都是抽象类,所以都需要通过其子类进行实现。
(父类引用指向子类对象 – 多态)
注意:
1、字节流:字节流就是将内容转为了字节形式进行传输, 1 字节 有 8 个二进制位组成,在底层,文件都是有二进制组成的,所以二进制可以传输任何类型的数据,进而 字节流也可以传输任何类型的数据。
2、字节流是 8 位通用字节流(可以处理任意类型,处理文本以外的其他文件)
3、字符流是 16 位 unicode 字符流(只用于处理字符,处理文本文件)
4、字符流:一般只用来处理字符,当我们传输图片的时候,转码的时候容易出现乱码,字节流也可以处理字符相关的文本,但是效率没有字符流更好。
输入流实现文本的读取:
在流到内存的时候因为我们不知道文件的具体大小,也就是字节数组的大小开多少比较合适
我们是不知道的,所以需要通过 in.available() 方法得到文件的大小,进而实现流动。
package io;
import java.io.*;
public class Demo03 {
public static void main(String[] args) throws IOException {
// 提高作用域,便于关闭
InputStream in = null;
try{
// InputStream 是一个抽象类,需要通过子类进行实现
in = new FileInputStream(new File("hello.txt"));
// 得到文件的总大小
System.out.println(in.available());
// 先将文件放到缓冲区里面,这里的缓冲区是一个 字节数组
byte[] buf = new byte[in.available()];
// 流到内存中
in.read(buf);
// 输出一下
System.out.println(new String(buf));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 防止出现空指针
if(in != null) in.close();
}
}
}
hello.txt 文本中的内容:
输出结果;
输出流实现将内容输出到文件中:
package io;
import java.io.*;
public class Demo04 {
public static void main(String[] args) throws IOException {
OutputStream out = null;
try {
// 与 输入流类似
out = new FileOutputStream(new File("d.txt"));
// 通过子节的方式将 hello123 读取到 d.txt 文件中
out.write("hello123".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(out != null) out.close();
}
}
}
d.txt
字节流实现文件的复制:
在实现文件的复制时,需要注意以下几点:
1、由于文件可能很大,可能有几个G,但是我们不可能一次开辟那么大的空间,所以可以分块进行流动,每次开辟一定的空间。
2、分块流动时可能会有多出来的一部分: 比如 135 byte,我们规定每次最多只能传输 10 byte,但是 最后会 只剩下 5 byte 还没有传输,这个时候缓冲区里面存储的还是上一次的 10byte,而新来的 5byte 只会替换前 5 个:如下图:
原文件:
复制后的文件:
可以清晰的看到,复制后的文件与原文件中的内容出现不一致,这个问题该怎么处理呢?
详见代码:
3、一定要记得关闭 输入流和输出流,否则会出现文件内容读不进去的尴尬!
package io;
import java.io.*;
public class Demo05 {
public static void main(String[] args) {
InputStream in = null;
OutputStream out = null;
try{
// 将原文件读到内存区
in = new FileInputStream(new File("a.txt"));
// 从 内存区 输出到 要复制的地方
out = new FileOutputStream(new File("b.txt"));
// 缓存区(每次都流动 10 byte)
byte[] buf = new byte[10];
int len = -1;
// in.read(buf) 返回值是流动到 内存区的 长度
while((len = in.read(buf) )!= -1) {
// 每次都流动的是 实际 的长度(这样可以避免出现文件不一致的情况)
out.write(buf,0,len);
}
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 一定要记得关 流
if(out != null) out.close();
if(in != null) in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符流实现文件的复制:
实现功能:
将a.txt文件中的内容 复制到 b.txt 文件中,并且将占位符替换掉。
package io;
import java.io.*;
public class Demo06 {
public static void main(String[] args) {
Reader in = null;
Writer out = null;
try {
// 字符输入流
in = new FileReader(new File("a.txt"));
// 字符输出流
out = new FileWriter(new File("b.txt"));
// 字节流是 字节数组作为缓冲区,字符流是 字符数组作为缓冲区
char[] buf = new char[4];
// 拼接字符串,由于 Sting 每次拼接时都要在 常量池中开辟新的空间,效率较低,所以我们选择用 StringBuffer
StringBuffer sb = new StringBuffer();
int len = -1;
while((len = in.read(buf)) != -1) {
sb.append(buf,0,len);
}
System.out.println(sb);
// 转换为 String 类型,替换相应的内容
String content = sb.toString();
content = content.replace("name","潘小蓝")
.replace("age","22")
.replace("address","HN");
// 输出到 相应文件中
out.write(content);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(in != null) in.close();
if(out != null) out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
效果图:
后记:
如果各位看官有疑问的或者有哪里解释的不清楚的,欢迎提出,在下会细心改正,大家共同进步,加油!!!