IO流
字节缓冲区流
字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入流数组这样的缓冲区效果,Java本身在设计的时候,在考虑到了这样的设计思想,所以提供字节缓冲区流:字节缓冲输出流 BufferedOutputStream 和 字节缓冲输入流 BufferedInputStream
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("a.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("hello".getBytes());
bos.close();
}
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
byte[] b = new byte[1024];
int len;
while((len = bis.read(b)) != -1){
System.out.print(new String(b,0,len));
}
bis.close();
}
⚠️ 缓冲字节流一次读写一个字节数组效率最高,重点学习!
字节流读数据可能出现的问题:字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为汉字是由两个字节组成的
由于字节流操作中文不是特别方便,所以Java提供了转换字节流 = 字节流 + 编码表 要使用统一的编码解码方式
String类中编码和解码问题
public static void main(String[] args) throws IOException {
String s = "你好";
byte[] b = s.getBytes("UTF-8");
System.out.println(Arrays.toString(b));
String ss = new String(b,"UTF-8");
System.out.println(ss);
}
什么是字节流?
字节流--传输过程中,传输数据的最基本单位是字节的流。
什么是字符流?
字符流--传输过程中,传输数据的最基本单位是字符的流。
字符编码方式不同,有时候一个字符使用的字节数也不一样,比如ASCLL方式编码的字符,占一个字节;而UTF-8方式编码的字符,一个英文字符需要一个字节,一个中文需要三个字节。
字节数据是二进制形式的,要转成我们能识别的正常字符,需要选择正确的编码方式。我们生活中遇到的乱码问题就是字节数据没有选择正确的编码方式来显示成字符。
从本质上来讲,写数据(即输出)的时候,字节也好,字符也好,本质上都是没有标识符的,需要去指定编码方式。
但读数据的时候,如果我们需要去“看数据”,那么字节流的数据需要指定字符编码方式,这样我们才能看到我们能识别的字符;而字符流,因为已经选择好了字符编码方式,通常不需要再改了(除非定义的字符编码方式与数据原有的编码方式不一致!)
字符流
InputStreamReader
可以把InputStream中的字节数据流根据字符编码方式转成字符数据流。它除了可以使用基类定义的函数,它自己还实现了以下函数:
read(char[] cbuf, int offset, int length) 从offset位置开始,读取length个字符到cbuf中,返回结果是实际读取的字符数,到达流的末尾时,返回-1
字符输入流案例
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
char[] chs = new char[1024];
int len;
while((len = isr.read(chs)) != -1){
System.out.print(new String(chs,0,len));
}
OutputStreamWriter
可以使我们直接往流中写字符串数据,它里面会帮我们根据字符编码方式来把字符数据转成字节数据再写给输出流,它相当于一个中介\桥梁。
字符输出流案例
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
char[] chs = {'a','b','c'};
osw.write(chs);
osw.flush();
osw.close();
}
上述方法过于麻烦,一般用以下的方法
FileReader
可以把FileInputStream中的字节数据转成根据字符编码方式转成字符数据流。
FileWriter
FileWriter与OutputStreamWriter功能类似,我们可以直接往流中写字符串数据,FileWriter内部会根据字符编码方式来把字符数据转成字节数据再写给输出流
复制文件案例
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
char[] chs = new char[1024];
int len;
while((len = fr.read(chs)) != -1){
fw.write(chs,0,len);
}
fw.close();
fr.close();
}
字符缓冲区流
BufferedWriter
比FileWriter还高级一点,它利用了缓冲区来提高写的效率
BufferedReader
可以把字符输入流进行封装,将数据进行缓冲,提高读取效率。它除了可以使用基类定义的函数,它自己还实现了以下函数:
- read(char[] cbuf, int offset, int length) :从offset位置开始,读取length个字符到cbuf中,返回结果是实际读取的字符数,到达流的末尾时,返回-1
- readLine() :读取一个文本行,以行结束符作为末尾,返回结果是读取的字符串。如果已到达流末尾,则返回 null
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
bw.write("hello");
bw.close();
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
char[] chs = new char[1024];
int len;
while((len = br.read(chs)) != -1){
System.out.print(new String(chs,0,len));
}
}
字符流的练习
五种方法:
- 基本字符流一次读写一个字符
- 基本字符流一次读写一个字符数组
- 缓冲字符流一次读写一个字符
- 缓冲字符流一次读写一个字符数组
- 缓冲字符串一次读写一个字符串
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
int ch;
while((ch = fr.read()) != -1){
fw.write(ch);
}
fw.close();
fr.close();
}
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
char[] chs = new char[1024];
int len;
while((len = fr.read(chs)) != -1){
fw.write(chs,0,len);
}
fw.close();
fr.close();
}
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bfw = new BufferedWriter(new FileWriter("b.txt"));
int b;
while((b = bfr.read()) != -1){
bfw.write(b);
}
bfw.close();
bfr.close();
}
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bfw = new BufferedWriter(new FileWriter("b.txt"));
char[] chs = new char[1024];
int len;
while((len = bfr.read(chs)) != -1){
bfw.write(chs,0,len);
}
bfw.close();
bfr.close();
}
public static void main(String[] args) throws IOException {
BufferedReader bfr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bfw = new BufferedWriter(new FileWriter("b.txt"));
String line;
while((line = bfr.readLine()) != null){
bfw.write(line);
bfw.newLine();
bfw.flush();
}
bfw.close();
bfr.close();
}
练习:把ArrayList集合内的字符串数据存储到文本文件
public static void main(String[] args) throws IOException {
ArrayList<String> arr = new ArrayList<String>();
arr.add("Hello");
arr.add("TIM");
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
for(String s: arr){
bw.write(s);
bw.newLine();
bw.flush();
}
bw.close();
}
练习:把文本文件内的字符读取到ArrayList集合内
public static void main(String[] args) throws IOException {
ArrayList<String> arr = new ArrayList<String>();
BufferedReader bw = new BufferedReader(new FileReader("b.txt"));
String s;
while((s = bw.readLine()) != null){
arr.add(s);
}
bw.close();
for(String s0: arr){
System.out.println(s0);
}
}
练习:把Animal对象数据写入文本文件
public static void main(String[] args) throws IOException {
Animal a0 = new Animal("Dog",2);
Animal a1 = new Animal("Cat",1);
ArrayList<Animal> arr = new ArrayList<Animal>();
arr.add(a0);
arr.add(a1);
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
for(Animal a: arr){
StringBuilder s = new StringBuilder();
s.append(a.getAge()).append(",").append(a.getName());
bw.write(s.toString());
bw.newLine();
bw.flush();
}
bw.close();
}
练习:把文本中的对象读取到集合
public static void main(String[] args) throws IOException {
BufferedReader bw = new BufferedReader(new FileReader("b.txt"));
ArrayList<Animal> arr = new ArrayList<Animal>();
String line;
while((line = bw.readLine()) != null){
String[] s = line.split(",");
Animal a = new Animal();
a.setName(s[1]);
a.setAge(Integer.parseInt(s[0]));
arr.add(a);
}
for(Animal a0:arr){
System.out.println(a0.getAge()+","+a0.getName());
}
}