一、流的概念
流是指一连串流动的数据信号,是以先进先出的方式发送和接收数据的通道。
二、流的分类
1)根据流动方向的不同,流分为输入流和输出流;
2)对于输入和输出流,由于传输格式的不同,又分为字节流和字符流:
字节流是指8位的通用字节流,以字节为基本单位,在java.io包中,对于字节流进行操作的类大部分继承于InputStream(输入字节流)类和OutputStream(输出字节流)类;
字符流是指16位的Unicode字符流,以字符(两个字节)为基本单位,非常适合处理字符串和文本,对于字符流进行操作的类大部分继承于Reader(读取流)类和Writer(写入流)类。
字节流的抽象基类:
• InputStream ,OutputStream。
字符流的抽象基类:
• Reader , Writer。
注:由这四个类派生出来的子类名称都是 以其父类名作为子类名的后缀。
• 如:InputStream的子类FileInputStream。
• 如:Reader的子类FileReader。
三、IO程序的书写
导入IO包中的类
进行IO异常处理
在finally中对流进行关闭
/*
IO异常的处理方式。
*/
import java.io.*;
class FileWriterDemo2{
public static void main(String[] args) {
FileWriter fw = null;
try{
fw = new FileWriter("demo.txt");
fw.write("abcdefg");
}
catch (IOException e){
System.out.println("catch:"+e.toString());
}
finally{
try{
if(fw!=null)
fw.close();
}
catch (IOException e){
System.out.println(e.toString());
}
}
}
}
四、字符流
1)、字符流——写入文件
那么数据的最常见体现形式是:文件。
那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter。 后缀名是父类名。 前缀名是该流对象的功能。
import java.io.*;
class FileWriterDemo{
public static void main(String[] args) throws IOException{
//创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt");
//调用write方法,将字符串写入到流中。
fw.write("abcde");
//刷新流对象中的缓冲中的数据。
//将数据刷到目的地中。
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地中。
//和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
fw.close();
}
}
2)、字符流——读取文件 FileReader
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReader fr = new FileReader("demo.txt");
//调用读取流对象的read方法。
char[] buf = new char[1024];
int len= 0;
while((len=fr.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
fr.close();
}
}
3)字符流的缓冲区
缓冲区的出现提高了对数据的读写效率。
对应类
• BufferedWriter
• BufferedReader
缓冲区要结合流才可以使用。
在流的基础上对流的功能进行了增强。
缓冲区的出现是为了提高流的操作效率而出现的。
所以在创建缓冲区之前,必须要先有流对象。
该缓冲区中提供了一个跨平台的换行符。
newLine();
BufferWriter步骤:
1.创建一个字符写入流对象
FileWriter fw=new FileWriter(“a.txt”);
2.将需要被提高效率的流对象作为参数传递给缓冲区的构造函数
bufferedWriter bufw=new BufferedWriter(fw);
buff.write(“asdasdas”);
bufw.newLine();//换行符,跨平台的
3.将缓冲区刷新
bufw.flush;
4.关闭缓冲区,就是在关闭缓冲区中的流对象
bufw.close();
BufferedReader步骤
1.创建一个字符写入流对象
FileReader fr=new FileReader (“a.txt”);
2.将需要被提高效率的流对象作为参数传递给缓冲区的构造函数
BufferedReader bufr=new BufferedReader (fr);
3.读取流对象:该缓冲区提供了一个一次读取一行的方法。当返回null时表示,文件读到末尾
String line=null;
while((line=bufr.readLine())!=null)
{
String s=line;}
4.关闭
bufr.close();
readLine()方法的原理:
无论是读一行,获取多个字符,最终都是在硬盘上一个一个读取,最终使用额还是read方法一次读一个的方法。
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
import java.io.*;
class BufferedWriterDemo
{
public static void main(String[] args) throws IOException{
//创建一个字符写入流对象。
FileWriter fw = new FileWriter("buf.txt");
//为了提高字符写入流效率。加入了缓冲技术。
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriter bufw = new BufferedWriter(fw);
for(int x=1; x<5; x++){
bufw.write("abcd"+x);
bufw.newLine();
bufw.flush();
}
//记住,只要用到缓冲区,就要记得刷新。
//bufw.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();
}
}
/*
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
*/
import java.io.*;
class BufferedReaderDemo{
public static void main(String[] args) throws IOException{
//创建一个读取流对象和文件相关联。
FileReader fr = new FileReader("buf.txt");
//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while((line=bufr.readLine())!=null){
System.out.print(line);
}
bufr.close();
}
}
Demo练习
/*
通过缓冲区复制一个.java文件。
*/
import java.io.*;
class CopyTextByBuf{
public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null;
try{
bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
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("写入关闭失败");
}
}
}
}
五、装饰类设计思路
当想要对已有的独享进行功能增强时,可以定义类,将已有的对象传入,基于已经有的功能,并提供加强功能,那么自定义的该类称为装饰类
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰的对象的功能,提供更强的功能。
以前是通过继承将每一个子类都具备缓冲功能。
那么继承体系会复杂,并不利于扩展。
现在优化思想。单独描述一下缓冲内容。
将需要被缓冲的对象。传递进来。也就是,谁需要被缓冲,谁就作为参数传递给缓冲区。
这样继承体系就变得很简单。优化了体系结构。
装饰模式比继承要灵活。避免了继承体系臃肿。
而且降低了类于类之间的关系。
装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。
所以装饰类和被装饰类通常是都属于一个体系中的。
/*
明白了BufferedReader类中特有方法readLine的原理后,
可以自定义一个类中包含一个功能和readLine一致的方法。
来模拟一下BufferedReader
*/
import java.io.*;
class MyBufferedReader extends Reader{
private Reader r;
MyBufferedReader(Reader r){
this.r = r;
}
//可以一次读一行数据的方法。
public String myReadLine()throws IOException{
//定义一个临时容器。原BufferReader封装的是字符数组。
//为了演示方便。定义一个StringBuilder容器。因为最终还是要将数据变成字符串。
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch=r.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;
}
/*
覆盖Reader类中的抽象方法。
*/
public int read(char[] cbuf, int off, int len) throws IOException{
return r.read(cbuf,off,len) ;
}
public void close()throws IOException{
r.close();
}
public void myClose()throws IOException{
r.close();
}
}
class MyBufferedReaderDemo{
public static void main(String[] args) throws IOException{
FileReader fr = new FileReader("buf.txt");
MyBufferedReader myBuf = new MyBufferedReader(fr);
String line = null;
while((line=myBuf.myReadLine())!=null){
System.out.println(line);
}
myBuf.myClose();
}
}
六、字节流
字节流:
InputStream OutputStream
基本操作与字符流类相同
但它不仅可以操作字符,还可以操作其他媒体文件
字节流的缓冲区
BufferedInputStream BufferedOutputStream
同样是提高了字节流的读写效率。
/*
需求,想要操作图片数据。这时就要用到字节流。
复制一个图片.
*/
/*
复制一个图片
思路:
1,用字节读取流对象和图片关联。
2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3,通过循环读写,完成数据的存储。
4,关闭资源。
*/
import java.io.*;
class CopyPic
{
public static void main(String[] args) {
FileOutputStream fos = null;
FileInputStream fis = null;
try{
fos = new FileOutputStream("c:\\2.bmp");
fis = new FileInputStream("c:\\1.bmp");
byte[] buf = new byte[1024];
int len = 0;
while((len=fis.read(buf))!=-1){
fos.write(buf,0,len);
}
}
catch (IOException e){
throw new RuntimeException("复制文件失败");
}
finally{
try{
if(fis!=null){
fis.close();
}
}
catch (IOException e){
throw new RuntimeException("读取关闭失败");
}
try{
if(fos!=null){
fos.close();
}
}
catch (IOException e){
throw new RuntimeException("写入关闭失败");
}
}
}
}
利用BufferedInputStream 复制mp3
/*
演示mp3的复制。通过缓冲区。
BufferedOutputStream
BufferedInputStream
*/
import java.io.*;
class CopyMp3{
public static void main(String[] args) throws IOException{
copy();
}
//通过字节流的缓冲区完成复制。
public static void copy()throws IOException{
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\1.mp3"));
int by = 0;
while((by=bufis.read())!=-1){
bufos.write(by);
}
bufos.close();
bufis.close();
}
}