简介
IO流用来处理设备之间数据传输的
流按操作数据分为字节流和字符流
- ASCII 编码表 电脑识别美国文字
- jbk 电脑识别中国文字
- 各个国家的文字进行重新的编排 用数字对应了一个Unicode码表 (无论什么字符,都用两个字节表示)
- utf-8 Unicode转换码表,对Unicode进行优化
一个字在jdk中对应的数字和utf-8中不一样,会产生乱码
为了解决 java在基于字节流的基础上出现了字符流,可以在内部融合编码表,可以自己指定查哪个码表(处理图片用字节流)
io流中有四个基类(都是抽象)
- 字节流
- inputStream 读
- outputstream 写
- 字符流
- reader
- writer
专门用于操作文件的writer子类对象FileWriter
创建一个FileWriter类对象,给对象一被初始化就必须要明确被操作的文件
而且该文件会被创建到指定目录下,如果该目录下已有该同名文件,将被覆盖
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
//其实该步就是在明确数据存放的目的地
FileWriter fw = new FileWriter("D:\\demo.text");
//调用write方法,将字符串写入到流中
fw.write("abcde");
//刷新流对象中的缓冲的数据
//将数据刷到目的地中
fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据
//将数据刷到目的地中。
fw.close();
}
}
对已有文件的数据续写
//传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写
FileWriter fw = new FileWriter("D:\\demo.text",true);
\r\n 表示在windows中的换行符
\n 表示在Linux中的换行符
专门用于操作文件的Reader子类对象FileReader
public class FileReaderDemo {
public static void main(String[] args) throws IOException {
//创建一个文件读取流对象,和指定名称的文件相关联
FileReader fr = new FileReader("D:\\demo.text");
//调用读取流对象的read方法,
//read() 一次读一个字符,而且会自动往下读,读完返回-1
int ch = 0;
while((ch = fr.read()) != -1) {
System.out.print((char)ch);
}
}
}
用read(char[])方法
public class FileReaderDemo2 {
public static void main(String[] args) throws IOException {
//创建一个文件读取流对象,和指定名称的文件相关联
FileReader fr = new FileReader("D:\\demo.text");
//定义一个字符数组,用于存储读到的字符
//该read(char[])返回的是读到字符个数,读完返回-1
char[] buf = new char[3];
int num = 0;
while((num = fr.read(buf)) != -1) {
System.out.print(new String(buf,0,num));
}
}
}
字符流的缓冲区(提高对数据的读写效率)
对应类
- BufferedWriter
- BufferedReader
缓冲区必须结合流使用,因为它是为了提高流的操作效率而出现的,所以在创建缓冲之前,必须要先有流对象
BufferedWriter
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
//创建一个字符写入流对象
FileWriter fw = new FileWriter("D:\\demo.text");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("abcde");
bw.newLine();//跨平台的换行符
//只要用到缓冲区,就要记得刷新
bw.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象
bw.close();
}
}
bw.newLine(); 跨平台的换行符
BufferedReader
为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲对象的构造函数
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("D:\\demo.text");
BufferedReader br = new BufferedReader(fr);
String line = null;
while((line=br.readLine())!=null) {
System.out.println(line);
}
}
}
readLine()方法为读取一行数据,遇到换行符此行读完,文件全部读完返回null
通过缓冲区复制一个.java文件
public class CopyTextByBuf {
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try {
bufr = new BufferedReader(new FileReader("D:\\demo.java"));
bufw = new BufferedWriter(new FileWriter("D:\\demo_copy.java"));
String line = null;
while((line = bufr.readLine())!=null) {
bufw.write(line);
bufw.newLine();
bufw.flush();
}
} catch (IOException e) {
throw new RuntimeException("读写失败");
}finally {
try {
if(bufr!=null)
bufr.close();
} catch (IOException e) {
throw new RuntimeException("读取关闭失败");
}
try {
if(bufw!=null)
bufw.close();
} catch (IOException e) {
throw new RuntimeException("写入关闭失败");
}
}
}
}
利用装饰者模式实现可以一次读一行数据的方法
class MyBufferedReader extends Reader{
private Reader fr;
MyBufferedReader(Reader fr){
this.fr = fr;
}
//可以一次读一行数据的方法
public String myReadLine() throws IOException {
//定义一个临时容器,原BufferReader封装的是字符数组
StringBuffer sb = new StringBuffer();
int ch = 0;
while((ch = fr.read()) != -1) {
if(ch == '\r')
continue;
if(ch == '\n')
return sb.toString();
else {
sb.append((char)ch);
}
}
//最后一行可能没有换行符
if(sb.length() != 0)
return sb.toString();
return null;
}
public void close() throws IOException {
fr.close();
}
public int read(char[] cbuf, int off, int len) throws IOException {
return fr.read(cbuf, off, len);
}
}
- 装饰者模式和继承的区别
装饰者模式更灵活。避免了继承体系臃肿,而且降低了类与类之间的关系