一:概述
1.概述
(1).IO流即为InputOutput的缩写,输入输出流
(2).IO流用来处理设备之间的数据传输 上传文件和下载文件
(3).Java对数据的操作是通过流的方式
(4).Java用于操作流的对象都在IO包中
数据流是一串连续不断的数据的集合,就像水管里的水流,在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流.
数据写入程序可以使一段一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流。
2.分类:
按流向分:
输入流 读取数据
输出流写出数据
按数据类型分:
字节流
字节输入流 读取数据
字节输出流 写出数据
字符流
字符输入流 读取数据
字符输出流 写出数据
注意:
一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的。
除非文件用windows自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流。
3.字节流和字符流的基类
字节流:InputStream和OutputStream
字符流:Reader和Writer
在IO流中,此四个类下的的子类名称都是以父类名作为子类名的后缀,
以前缀为其功能;如InputStream子类FileInputStream;Reader子类FileReader
二:字节流
字节流可以用来操作字符数据,也可以操作字节数据类型。
读写字节流: InputStream 输入流(读)
OutputStream 输出流(写)
IO流是用于操作数据的,那么数据的最常见体现形式是文件,在Java中操作文件的流是FileInputStream和FileOutputStream
1.字节输出流操作步骤:
A:创建字节输出流对象,它会调用系统功能区创建文件,并创建字节流对象,指向这个文件,如果文件已存在会被覆盖。
B:写数据,调用write()方法将数据写入
C:释放资源,关闭此文件输出流并释放与此流有关的所有系统资源,原因是让流对象变成垃圾,这样就可以被垃圾回收器回收,
通知系统去释放跟该文件相关的资源,流关闭后不能再写入数据
如何实现数据的换行?
没有换行是因为你值写了字节数据,并没有写入换行符号。
如何实现呢?写入换行符号。
因为不同的系统针对不同的换行符号识别是不一样的?
windows:\r\n
linux:\n
Mac:\r
而一些常见的个高级记事本,是可以识别任意换行符号的。
如何实现数据的追加写入?
用构造方法带第二个参数是true的情况即可
注意:
1.其实java自身不能写入数据,而是调用系统内部方式完成数据的书写,使用系统资源后,一定要关闭资源。
2.文件的数据的续写是通过构造函数FileOutputStream(String name, boolean append) ,在创建对象时,传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。(windows系统中的文件内换行用\r\n两个转义字符表示,在linux系统中只用\n表示换行)
3.由于在创建对象时,需要指定创建文件位置,如果指定的位置不存在,就会发生IOException异常,所以在整个步骤中,需要对IO异常进行try处理。
FileOutputStream的构造方法:
FileOutputStream(File 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 class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("fos.txt");
// 调用write()方法
fos.write(97); //97 -- 底层二进制数据 -- 通过记事本打开 -- 找97对应的字符值 -- a
fos.write(57);
fos.write(55);
fos.write("\r\n".getBytes());
//public void write(byte[] b):写一个字节数组
byte[] bys={97,98,99,100,101};
fos.write(bys);
fos.write("\r\n".getBytes());
//public void write(byte[] b,int off,int len):写一个字节数组的一部分
fos.write(bys,1,3);
//写数据
fos.write("hello,IO".getBytes());
fos.write("java".getBytes());
//释放资源
fos.close();
}
}
因为在IO流中有非常多的异常,所以需要我们处理 ,加入异常处理的代码
public class FileOutputStreamDemo2 {
public static void main(String[] args) {
// 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值
FileOutputStream fos = null;
try {
fos = new FileOutputStream("foss.txt");
fos.write("java".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 如果fos不是null,才需要close()
if (fos != null) {
// 为了保证close()一定会执行,就放到这里了
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
2.字节输入流操作步骤:
A:创建字节输入流对象
B:调用read()方法读取数据,并把数据显示在控制台
C:释放资源
FileInputStream 的构造方法
FileInputStream(File file):传入一个文件
FileInputStream(String name):传入文件的路径
读取数据的方式:
A:int read():一次读取一个字节,读到末尾会返回-1.
B:int read(byte[] b):一次读取一个字节数组。返回值其实是实际读取的字节个数。
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
// FileInputStream(String name)
// FileInputStream fis = new FileInputStream("fis.txt");
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");
/*
一次读个字节
int by = 0;
// 读取,赋值,判断
while ((by = fis.read()) != -1) {
System.out.print((char) by);
}
*/
//一次读个字节数组
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}
// 释放资源
fis.close();
}
}
//字节流复制数据练习
/*
需求:把c盘下的a.txt的内容复制到d盘下的b.txt中
数据源:
c:\\a.txt -- 读取数据-- FileInputStream
目的地:
d:\\b.txt -- 写出数据 -- FileOutputStream
*/
public class CopyFileDemo1 {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("c:\\a.txt");
// 封装目的地
FileOutputStream fos = new FileOutputStream("d:\\b.txt");
// 复制数据
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
// 释放资源
fos.close();
fis.close();
}
}
public class CopyFileDemo2 {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("c:\\a.txt");
FileOutputStream fos = new FileOutputStream("d:\\b.txt");
// 复制数据
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
// 释放资源
fos.close();
fis.close();
}
}
/*
需求:把e:\\11.jpg内容复制到当前项目目录下的22.jpg中
数据源:
e:\\11.jpg --读取数据--FileInputStream
目的地:
mn.jpg--写出数据--FileOutputStream
*/
public class CopyImageDemo {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("e:\\11.jpg");
// 封装目的地
FileOutputStream fos = new FileOutputStream("22.jpg");
// 复制数据
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
// 释放资源
fos.close();
fis.close();
}
}
public class CopyImageDemo2{
public static void main (String [] args){
// 封装数据源
FileInputStream fis = new FileInputStream("e:\\11.jpg");
// 封装目的地
FileOutputStream fos = new FileOutputStream("22.jpg");
// 复制数据
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
// 释放资源
fos.close();
fis.close();
}
}
/*
需求:把e:\\视频.mp4复制到当前项目目录下的copy.mp4中
数据源:
e:\\视频.mp4--读取数据--FileInputStream
目的地:
copy.mp4--写出数据--FileOutputStream
*/
public class CopyMp4Demo {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("e:\\视频.mp4");
// 封装目的地
FileOutputStream fos = new FileOutputStream("copy.mp4");
// 复制数据
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
// 释放资源
fos.close();
fis.close();
}
}
public class CopyMp4Demo {
public static void main(String[] args) throws IOException {
// 封装数据源
FileInputStream fis = new FileInputStream("e:\\视频.mp4");
// 封装目的地
FileOutputStream fos = new FileOutputStream("copy.mp4");
// 复制数据
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
// 释放资源
fos.close();
fis.close();
}
}
3.字节缓冲流
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
这是加入了数组这样的缓冲区效果,java本身在设计的时候,
也考虑到了这样的设计思想,所以提供了字节缓冲区流
字节缓冲输出流
BufferedOutputStream
字节缓冲输入流
BufferedInputStream
BufferedInputStream(InputStream in) :创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedInputStream(InputStream in, int size) :创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。
BufferedOutputStream(OutputStream out) :创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size) :创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。
构造方法可以指定缓冲区的大小,但是我们一般用不上,因为默认缓冲区大小就足够了。
为什么不传递一个具体的文件或者文件路径,而是传递一个OutputStream对象呢?
原因很简单,字节缓冲区流仅仅提供缓冲区,为高效而设计的。但是呢,真正的读写操作还得靠基本的流对象实现。
public class BufferedOutputStreamDemo {
public static void main(String[] args) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("bos.txt"));
// 写数据
bos.write("hello".getBytes());
// 释放资源
bos.close();
}
}
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
"bos.txt"));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}
// 释放资源
bis.close();
}
}
/*
* 需求:把e:\\视频.mp4复制到当前项目目录下的copy.mp4中
*
* 字节流四种方式复制文件:
* 基本字节流一次读写一个字节: 共耗时:117235毫秒
* 基本字节流一次读写一个字节数组: 共耗时:156毫秒
* 高效字节流一次读写一个字节: 共耗时:1141毫秒
* 高效字节流一次读写一个字节数组: 共耗时:47毫秒
*/
public class CopyMp4Demo {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
// method1("e:\\视频.mp4", "copy1.mp4");
// method2("e:\\视频.mp4", "copy2.mp4");
// method3("e:\\视频.mp4", "copy3.mp4");
method4("e:\\视频.mp4", "copy4.mp4");
long end = System.currentTimeMillis();
System.out.println("共耗时:" + (end - start) + "毫秒");
}
// 高效字节流一次读写一个字节数组:
public static void method4(String srcString, String destString)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
srcString));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destString));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
bis.close();
}
// 高效字节流一次读写一个字节:
public static void method3(String srcString, String destString)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
srcString));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destString));
int by = 0;
while ((by = bis.read()) != -1) {
bos.write(by);
}
bos.close();
bis.close();
}
// 基本字节流一次读写一个字节数组
public static void method2(String srcString, String destString)
throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
fos.close();
fis.close();
}
// 基本字节流一次读写一个字节
public static void method1(String srcString, String destString)
throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
fos.close();
fis.close();
}
}
三、字符流
1.转换流
由于字节流操作中文不是特别方便,所以,java就提供了转换流。
字符流=字节流+编码表。
2.编码表
由字符及其对应的数值组成的一张表
常见编码表
ASCII/Unicode 字符集
ISO-8859-1
GB2312/GBK/GB18030
BIG5
UTF-8
3.字符串中的编码问题
编码
把看得懂的变成看不懂的
解码
把看不懂的变成看得懂的
编码问题简单,只要编码解码的格式是一致的。
String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组
byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组
编码:把看得懂的变成看不懂的
String -- byte[]
解码:把看不懂的变成看得懂的
byte[] -- String
<pre name="code" class="java">public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "你好";
// String -- byte[]
byte[] bys = s.getBytes(); // [-60, -29, -70, -61]
// byte[] bys = s.getBytes("GBK");// [-60, -29, -70, -61]
// byte[] bys = s.getBytes("UTF-8");// [-28, -67, -96, -27, -91, -67]
System.out.println(Arrays.toString(bys));
// byte[] -- String
String ss = new String(bys); // 你好
// String ss = new String(bys, "GBK"); // 你好
// String ss = new String(bys, "UTF-8"); // ???
System.out.println(ss);
}
}
1.转换流 InputStreamReader 和 OutputStreamWriter InputStreamReader 的构造方法 InputStreamReader(InputStream in) :创建一个使用默认字符集的 InputStreamReader。 InputStreamReader(InputStream in, String charsetName) :创建使用指定字符集的 InputStreamReader。 InputStreamReader 读数据方法 public int read():一次读一个字符 public int read(char[] cbuf):一次读一个字符数组 字符流操作要注意的问题 flush()的作用:用于刷新该流的缓冲区,将数据从内存刷到文件中。 flush()和close()的区别 面试题:close()和flush()的区别? A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。 B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。 OutputStreamWriter 的构造方法 OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流 OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流 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):写一个字符串的一部分
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
// 创建对象
InputStreamReader isr = new InputStreamReader(new FileInputStream(
"StringDemo.java"));
// 一次读取一个字符
// int ch = 0;
// while ((ch = isr.read()) != -1) {
// System.out.print((char) ch);
// }
// 一次读取一个字符数组
char[] chs = new char[1024];
int len = 0;
while ((len = isr.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
// 释放资源
isr.close();
}
}
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
// 创建对象
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(
"osw2.txt"));
// 写数据
// public void write(int c):写一个字符
// osw.write('a');
// osw.write(97);
// public void write(char[] cbuf):写一个字符数组
// char[] chs = {'a','b','c','d','e'};
// osw.write(chs);
// public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
// osw.write(chs,1,3);
// public void write(String str):写一个字符串
// osw.write("今天天气真好");
// public void write(String str,int off,int len):写一个字符串的一部分
osw.write("今天天气真好", 2, 3);
// 刷新缓冲区
osw.flush();
// osw.write("今天天气真好", 2, 3);
// 释放资源
osw.close();
// java.io.IOException: Stream closed
// osw.write("今天天气真好", 2, 3);
}
}
2.FileReader和FileWriter
转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。
FileWriter
FileWriter(File file) :根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(File file, boolean append) :根据给定的 File 对象构造一个 FileWriter 对象。
FileWriter(String fileName) :根据给定的文件名构造一个 FileWriter 对象。
ileWriter(String fileName, boolean append) :根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。
FileReader
FileReader(File file):在给定从中读取数据的 File 的情况下创建一个新 FileReader。
FileReader(String fileName) :在给定从中读取数据的文件名的情况下创建一个新 FileReader。
读写字符流步骤
1.创建一个FileWriter,FileReader对象,
2.调用方法,将读取到的数据写入到流中。
3.调用flush()方法,刷新该流的缓冲,将数据刷新到目的地中。
4.调用close()方法,关闭流资源。
/*
需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中
数据源:
a.txt -- 读取数据 -- 字符转换流 -- InputStreamReader -- FileReader
目的地:
b.txt -- 写出数据 -- 字符转换流 -- OutputStreamWriter -- FileWriter
*/
public class CopyFileDemo2 {
public static void main(String[] args) throws IOException {
// 封装数据源
FileReader fr = new FileReader("a.txt");
// 封装目的地
FileWriter fw = new FileWriter("b.txt");
// 一次一个字符
// int ch = 0;
// while ((ch = fr.read()) != -1) {
// fw.write(ch);
// }
// 一次一个字符数组
char[] chs = new char[1024];
int len = 0;
while ((len = fr.read(chs)) != -1) {
fw.write(chs, 0, len);
fw.flush();
}
// 释放资源
fw.close();
fr.close();
}
}
3.字符缓冲流
BufferedWriter基本用法
BufferedWriter:字符缓冲输出流
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
BufferedWriter(Writer out)
BufferedReader基本用法
从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
BufferedReader(Reader in)
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// 创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
// 方式1
// int ch = 0;
// while ((ch = br.read()) != -1) {
// System.out.print((char) ch);
// }
// 方式2
char[] chs = new char[1024];
int len = 0;
while ((len = br.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
// 释放资源
br.close();
}
}
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
// BufferedWriter(Writer out)
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
// new FileOutputStream("bw.txt")));
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
bw.write("hello");
bw.write("world");
bw.write("java");
bw.flush();
bw.close();
}
}
特殊功能
BufferedWriter
void newLine():根据系统来决定换行符
BufferedReader
String readLine():一次读一行数据,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
//字符缓冲流特殊功能复制文本文件
public class CopyFileDemo2 {
public static void main(String[] args) throws IOException {
// 封装数据源
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// 读写数据
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
// 释放资源
bw.close();
br.close();
}
}
四、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):一次写一个字符串
五、流操作的基本规律
流对象很多,不知道该用哪一个?
通过三个明确来完成。
1.明确源和目的
源:输入流: InputStream Reader
目的:输出流: OutputStream Writer
2.明确操作的数据是否是纯文本
是:字符流
否:字节流
3.当体系明确后,再明确要使用哪个具体的对象
通过设备来进行操作
源设备:内存、硬盘、键盘
目的设备:内存、硬盘、控制台
1.将一个文本文件的数据存储到另一个文件中,复制文件
源:因为是源,所以使用读取流,InputStream Reader
是不是操作文本文件
是!使用Reader
这样体系就明确了,
接下来明确要使用该体系中的那个对象。
明确设备:硬盘中的一个文件
Reader体系中可以操作文件的对象是 FileReader;
是否需要提高效率:
是!加入Reader体系中的缓冲区 : BufferedReader
即:
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
目的:因为是目的,所以使用写入流。OutputStream Writer
是不是操作文件
是!使用Writer
接下来明确要使用该体系的那个对象
明确设备:硬盘上的一个文件
Writer体系中可以操作文件的对象是 FileWriter
是否需要提高效率:
是!加入Writer体系中的缓冲区: BufferedWriter
即:
BufferedWriter bufw = new BufferedWriter (new FileWriter("b.txt"));
2.需求:将键盘录入的数据保存到一个文件中
这个需求中有源有目的,分别分析
源:InputStream 、Reader
是不是纯文本 是!使用Reader
设备是 键盘: 对应的对象是 System.in
不是应该选择Reader吗? 但是System.in对应的是字节输入流,
为了操作键盘的文本数据更方便,将字节流转成字符流,按照字符串操作更方便
所以既然明确了Reader,那么就将System.in转换成Reader
用Reader体系中的转换流 InputStreamReader
即:
InputStreamReader isr = new InputStreamWriter(System.in);
需要高效吗? 需要 BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是纯文本 是! Writer
设备:硬盘中的文件,使用对象为FileWriter
FileWriter fw = new FileWriter("a.txt");
需要高效吗? 需要 使用BufferedWriter
BufferedWriter bufr = new BufferedWriter (fw);
*****************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存入文件中
目的:OutputStream Writer
是否是纯文本? 是!使用Writer
设备:硬盘中的一个文件、 使用FileWriter
但是FileWriter 使用的是默认的编码表 GBK
但是存储的时候需要加入指定的编码表,utf-8,而指定的编码表只有转换流才可以指定
所以要使用的对象是OutputStreamWriter
而该转换流对象要接收一个字节输出流,而且还可以操作文件的字节输出流,FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter (new FileInputStream ("a.txt","utf-8"));
需要高效吗?需要 使用 BufferedWriter
BufferedWriter bufw = new BufferedWriter (osw);
记住:转换流什么时候使用,字符和字节之间的桥梁,通常涉及到字符编码转换时,需要用到转换流.
六、装饰设计模式
1、简述
当想对已有对象进行功能增强时,可定义类:将已有对象传入,基于已有对象的功能,
并提供加强功能,那么自定义的该类称之为装饰类。
2、特点
装饰类通常都会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
3、装饰和继承的区别:
1.以前通过继承将每一个类都具备缓冲功能,现在优化思想,单独描述一个缓冲内容,将需要被缓冲的对象,传递进来,
也就是谁需要被缓冲,谁就作为参数传递给缓冲区。这样的继承体系就变得简单,优化了体系结构。
2.装饰模式比继承要灵活,避免了集成体系臃肿,而且降低了类与类之间的关系
3.装饰类因为增强已有的对象,具备的功能和已有的是相同的,只不过提供了更强的功能。
所以装饰类和被装饰类通常都是属于一个体系中的
注:在定义类的时候,不要以继承为主;可通过装饰设计模式进行增强类功能。
灵活性较强,当装饰类中的功能不适合,可再使用被装饰类的功能。
上面讲到的MyBufferedReader的例子就是最好的装饰设计模式的例子。