------<a href="http://www.itheima.com"target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
IO(Input,Output)流
流按流向分为:输入流,输出流
他们操作的数据分为两种:字节流,字符流。
字节流的两个基类(抽象类)
InputStream(输入:读取) OutputStream(输出:写入)
字符流的两个基类(抽象类)
Reader(读者) Writer(写者)
字符流的特点
既然IO流是用于操作数据的,那么数据最常见的体现形式是:文件
那么先以操作一个文件来演示
需求:在硬盘上,创建一个文件并写入一些文字数据。
代码演示:
//导入IO包
import java.io.*;
class Yanshi
{
public static void main(String[] args)throws IOException
{
//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件
//而且该文件会被创建到指定的目录下.如果该目录下已有同名的文件,将被覆盖掉。
//其实这个步骤就是在明确创建数据要存放的目的地。
FileWriter fw = newFileWriter("g:\\ys\\demo.txt");
//该步骤,调用writer方法,将字符串写入到流中。
//运行这一步时,数据还没有被写到硬盘指定位置上的文件中。
fw.write("abcde");
//刷新流对象中的缓冲中的数据,将数据刷到目的地中
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到指定位置的目的地中
fw.close();
/*
flush();和close();的区别:
flush:刷新后,流可以继续使用。
close:刷新后,流就会关闭。
*/
}
}
IO异常的基本处理方式
代码演示:
//导入IO包
import java.io.*;
class Yanshi
{
publicstatic void main(String[] args)
{
//在try外边建立引用。
FileWriterfw = null;
//在try里面进行初始化
//这样fw变量才能作用于整个函数。
try
{
//指定一个不存在的盘符
fw= new FileWriter("k:\\ys\\demo.txt");
fw.write("abcdefg");
}
catch(IOExceptione)
{
//接收到异常并打印
System.out.println("catch:"+e.toString());
}
finally
{
try
{
//因为fw对象为空的情况下调用close();方法依然是有问题的。
//所以一定判断下fw是否为空,才决定是否执行fw.close();
//提高了代码的健壮性。
if(fw!=null)
fw.close();
}
catch(IOExceptione)
{
System.out.println(e.toString());
}
}
}
}
IO(文件的续写)
代码演示:对已有文件的续写
//导入IO包
import java.io.*;
class Yanshi
{
publicstatic void main(String[] args)throws IOException
{
//传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据的续写。
FileWriterfw = new FileWriter("g:\\ys\\demo.txt",true);
//\r\n代表着回车换行
fw.write("nihao\r\nxiexie");
fw.close();
}
}
IO流(文本文件读取)
代码演示:
//导入IO包
import java.io.*;
class Yanshi
{
publicstatic void main(String[] args)throws IOException
{
//创建一个文件读取流对象,和指定位置名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReaderfr = new FileReader("g:\\ys\\demo.txt");
//调用读取流对象的方法。
//read()方法一次读取一个字符。
//如果下一行fr重复调用read();方法,会自动读取下一个字符。
//intch = fr.read();
//将int类型强转成char,进行输出。
//System.out.println((char)ch);
//如果要读取一个文件的数据,上面方法对一个文件的读取方式太繁琐
/*
//解决方法一:
//因为当read();方法读到文件末尾处,会返回-1.
//所以只要定义当ch==-1时,就结束运行。
int ch=0;
while((ch=fr.read())!=-1)
{
System.out.println((char)ch);
}
*/
//解决方法二:通过字符数组进行读取。
//定义一个字符数组。用于存储读到字符
char[]buf = new char[1024];
intnum = 0;
while((num= fr.read(buf))!=-1)
{
System.out.print(newString(buf,0,num));
}
fr.close();
}
}
IO流(copy)
将C盘下的一个文本文件复制到D盘。
复制到的原理:
其实就是将C盘文下的一个文件进行数据读取,然后再将数据输入到D盘上的一个文件。
代码演示:
//导入IO包
import java.io.*;
class Yanshi
{
public static void main(String[] args)throwsIOException
{
copy_2();
}
public static void copy_2()
{
FileWriter fw = null;
FileReader fr = null;
try
{
fw = newFileWriter("g:\\haha_copy.java");
fr = new FileReader("haha.java");
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1)
{
fw.write(buf,0,len);
}
}
catch(IOException e)
{
throw new RuntimeException("读写失败了");
}
finally
{
if(fr!=null)
try
{
fr.close();
}
catch(IOException e)
{
}
if(fw!=null)
try
{
fw.close();
}
catch(IOException e)
{
}
}
}
/*
//从C盘读一个字符,就往D盘写一个字符。
public static void copy_1()throws IOException
{
//创建目的地
FileWriter fw =newFileWriter("g:\\person_copy.java");
//与已有文件关联
FileReader fr =newFileReader("person.java");
int ch = 0;
while((ch=fr.read())!=-1)
{
fw.write(ch);
}
fw.close();
fr.close();
}
*/
}
字符写入流的缓冲区
BufferedWriter(Writer out)
缓冲区的出现是为了提高流的操作效率而出现的
(所以创建缓冲区之前必须先有流对象)
代码演示:
import java.io.*;
class Yanshi
{
public static void main(String[]args)throws IOException
{
//创建一个字符写入流对象
FileWriter fw = newFileWriter("G:\\buf.txt");
//为了提高字符写入流的效率加入了缓冲技术.
//只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
BufferedWriter bufw = newBufferedWriter(fw);
bufw.write("abcde");
//其实关闭缓冲区,就是在关闭缓冲区的流对象,也可以理解为缓冲区去和流对象是一起关闭的
bufw.close();
/*
小知识点:该缓冲区中提供了一个跨平台的换行符newLine();
只有用到缓冲区对象才能用到这个newLine();方法
*/
}
}
字符读取流的缓冲区(BufferedReader)
它本身就是Reader的一个子类(具备了Reader所有方法)
代码演示:
import java.io.*;
class Yanshi
{
public static void main(String[] args)throws IOException
{
//创建一个读取流的对象并和文件相关联
FileReader fr = newFileReader("g:\\buf.txt");
//为了提高效率,加入缓冲技术。将字符读取流对流作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = newBufferedReader(fr);
/*
该缓冲区提供了一个一次读一行的方法readLine();,方便于对文本数据的获取
当返回null时,表示已经读到文件末尾。
*/
String line = null;
//当bufr.readLine();读到文件末尾处,返回的是null,
//所以定义当bufr.readLine();在不等于null的情况下就一直进行读取的动作。
while((line=bufr.readLine())!=null)
{
System.out.println("line:"+line);
}
bufr.close();
}
}
通过缓冲区复制文本文件的演示:
import java.io.*;
class Yanshi
{
public static void main(String[]args)throws IOException
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(newFileReader("g:\\person.java"));
bufw = new BufferedWriter(newFileWriter("g:\\person_copy.java"));
String line = null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
//注意:readLine方法返回的时候只返回回车符之前的数据内容
//并不返任何的行终止符。
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的原理后
//自定义一个读取流缓冲区,(MyBufferedReader)来模拟BufferedReader
代码演示:
import java.io.*;
class MyBufferedReader
{
private FileReader r;
MyBufferedReader(FileReader r)
{
this.r = r;
}
//可以一次读一行数据的方法
public String myReadLine()throwsIOException
{
//定义一个临时容器。原BufferedReader封装的是字符数组
//为了演示方便,定义一个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;
}
public void myClose()throws IOException
{
r.close();
}
}
class Yanshi
{
public static void main(String[]args)throws IOException
{
FileReader fr = newFileReader("g:\\person.java");
MyBufferedReader myBuf = newMyBufferedReader(fr);
String line = null;
while((line=myBuf.myReadLine())!=null)
{
System.out.println(line);
}
myBuf.myClose();
}
}
以上这段程序演示了对read();方法的功能进行了加强,
(这种模式可以称为:装饰设计模式)
当想要对已有的对象进行功能增强时,
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。
那么自定义的该类,就称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象,
并基于被装饰的对象的功能,提供更强的功能。
根据以上代码,发现装饰设计模式。和继承体系有些相似,那么它们的区别是什么?
装饰模式比继承要灵活很多,避免了集成体系的臃肿。
而且将降低了类与类之间的关系。
装饰类因为是增强已有对象,具备的功能和已有对象是相同的,只不过提供了更强功能
使用,装饰类和被装饰类通常都属于一个体系中。