------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
其中字符流的抽象基类是Reader和Writer。
一.Writer子类FileWriter
IO流是用于操作数据的,数据的最常见体现形式是文件。专门用于操作文件的Writer子类对象,FileWriter.后缀名是父类名,前缀名是该流对象的功能。构造方法不为空,必须创建文件才可以操作文件。
1)具体步骤如下:
1.导入io包
2.创建一个FileWriter对象,该对象一初始化就必须要明确被操作的文件。而且,该文件会被创建到指定目录下。如果,该目录下已经有了重名文件,那么将会被覆盖。其实,这一步就是明确数据存放的目的地。
3.调用write方法,将字符串写入到流中。
4.刷新流对象中缓存中的数据,将数据刷到目的地中。
5.close关闭流资源,但是关闭之前会刷新一次内部的缓存中的数据。close和flush的区别是,使用flush之后,流还可以继续使用,而close使用之后,会将流关闭。
其中2,3,5步骤都会产生IOException异常。
import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
FileWriter fw = new FileWriter("demo.txt");
fw.write("asdfghjkl");
fw.flush();//close
}
}
2)IO异常的处理方式
其中,上面步骤的2,3,5都要写在try语句块中,但是5又必须写在finally语句块中,这是因为必须关闭流资源。而且,在try-catch-finally语句块之前,要先申明变量为null,否则在finally语句块中没有变量。
在finally语句中要先申明变量不为空,因为对象为null不能调用close,再去用close方法。
import java.io.*;
class FileWriterDemo2
{
public static void main(String[] args)
{
FileWriter fw = null;
try
{
fw = new FileWriter("demo.txt");
fw.write("ijnokm");
}
catch (IOException e)
{
System.out.println(e.toString());
}
finally
{
try
{
if(fw != null)
fw.close();
}
catch (IOException e)
{
System.out.println(e.toString());
}
}
}
}
3)在已有文件数据的续写
FileWriter("file",true)传递一个true参数,代表不覆盖已有的文件。并在已有文件的末尾处进行数据续写。
其中在Windows的记事本中,想要换行\r\n
二.Reader子类FileReader
具体步骤:
1.创建一个文件读取流对象,和指定名称的文件相关联。要保证该文件是存在的,如果不存在就会发生异常FileNotFoundException(IOException子类)
2.调用读取流对象的read方法。
3.关闭close流。
其中,int read()方法一次只读一个字符,而且会自动往下读。读到超出范围时会返回-1.
int read(char[] cbuf)char的长度通常是1024,返回读取的字符数,如果已经达到末尾,返回-1.
read(char[] , int start , int end)返回开始结尾的个数。
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("demo.txt");
while(true)
{
int ch = fr.read();
if(ch == -1)
break;
System.out.println("ch="+(char)ch);
}
fr.close();
}
}
import java.io.*;
class FileReaderDemo2
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("demo.txt");
char[] buf = new char[1024];
//int num = fr.read(buf);
//System.out.println("num="+num+"..."+new String(buf));
int num = 0;
while((num = fr.read(buf)) != -1)
{
System.out.println("num = "+num+new String(buf,0,num));
}
fr.close();
}
}
三.Copy文本文件
1)复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。
具体步骤:
1.在D盘创建一个文件。用于存储C盘文件的数据。
2.定义读取流和C盘文件相关联。
3.通过不断地读写完成数据的存储。
4.关闭资源。
import java.io.*;
class CopyTxt
{
public static void main(String[] args) //throws IOException
{
copy_2();
}
public static void copy_2()
{
FileWriter fw = null;
FileReader fr = null;
try
{
fw = new FileWriter("RuntimeDemo_copy_2.txt");
fr = new FileReader("RuntimeDemo.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(fw != null)//当fw,没有创建文件时,fw为空,不能调用close
try
{
fw.close();
}
catch (IOException e)
{
}
if(fr != null)
try
{
fr.close();
}
catch (IOException e)
{
}
}
}
public static void copy_1() throws IOException
{
FileWriter fw = new FileWriter("RuntimeDemo_copy_1.txt");
FileReader fr = new FileReader("RuntimeDemo.java");
int num = 0;
while((num = fr.read()) != -1)
{
fw.write(num);
}
fw.close();
fr.close();
}
}
四.字符流的缓冲区BufferedWriter和BufferedReader
缓冲区的出现是为了提高流的控制效率而出现的。(eg:水一滴一滴的往下滴,直接用嘴喝不如直接用杯子接满水再一起喝来的方便)所以在创建缓冲区之前,必须要现有流对象。只要将需要被提高效率的流对象作为参数传递给缓冲区的构造函数即可。
缓冲区的close方法,就是关闭缓冲区的流对象。
BufferedWriter该缓冲区提供了一个跨平台的换行符。newLIne();
BufferedReader该缓冲区提供了一个非常重要的方法String readLine(),读取一个文本行,返回改行内容的字符串,不包含任何终止符,如果已经到达末尾,则返回null,该方法方便于文本数据的获取。
import java.io.*;
class BufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("buf.txt");
BufferedReader brfr = new BufferedReader(fr);
String line = null;
while((line = brfr.readLine()) != null)
{
System.out.println(line);
}
brfr.close();
}
}
通过缓冲区复制一个.java文件:
1.创建BufferedReader对象,读流对象放入缓冲区。创建BufferedWriter对象,写流放入缓冲区中。
2. bufw.write(bufr.readLine());
3. bufw.newLine();
4. bufw.close();
5. bufr.close();
import java.io.*;
class CopyTextByBuf
{
public static void main(String[] args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader("BufferedReaderDemo.java"));
bufw = new BufferedWriter(new FileWriter("BUfferedReaderDemo_Copy.txt"));
String line = null;
while((line = bufr.readLine()) != null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("读写异常");
}
finally
{
if(bufw != null)
try
{
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException("读异常");
}
if(bufr != null)
try
{
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("xie异常");
}
}
}
}
readLine方法的原理:
无论读一行,获取多个字符。其实最终都是在硬盘上一个一个读取。所以最终使用的还是read方法一次读一个的方法。
五.装饰设计模式
当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的类称为装饰类。
具体步骤:
1.在装饰类的构造函数中传入原有类的对象
2.在装饰类内写一个方法,该方法为原有方法的增强版。
3.建立装饰类的对象和原类的对象,用装饰类的构造函数中传入原有类的对象。
4.装饰方法调用。
class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
SuperPerson sp = new SuperPerson(p);
sp.superChifan();
}
}
class Person
{
public void chifan()
{
System.out.println("吃饭");
}
}
class SuperPerson
{
private Person p;
SuperPerson(Person p)
{
this.p = p;
}
public void superChifan()
{
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
System.out.println("一根烟");
}
}
装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象提供更强的功能。
eg:BufferedReader的readLine()就是装饰了FileReader的read()
装饰与继承的区别:
装饰模式比继承更加灵活,而且降低了类与类之间的关系。装饰类因为增强了已有的对象,具备的功能和已有的是相同的,只不过是提供了更强的功能。所以装饰类和被装饰类通常是属于一个体系的。
eg:
MyRead
---MyTextRead
---MyMediaRead
--MyBufferedReader装饰类
class MyBufferedReader extends MyRead
{
MyBufferedReader(MyRead r){}//通过多态找到参数的共同类型,提高扩展性
}
BufferedReader的子类LineNumberReader类是跟踪行号的缓冲字符输入流,他有两个方法getLineNumber();获取行号;setNumber();设置行号。
用装饰类重写后
import java.io.*;
class MyLineNumberReader
{
private Reader r;
private int lineNumber;
MyLineNumberReader(Reader r)
{
this.r = r;
}
public String myReadLine() throws IOException
{
lineNumber ++;
StringBuilder sb = new StringBuilder();
int num = 0;
while((num = r.read()) != -1)
{
if(num == '\r')
continue;
if(num == '\n')
return sb.toString();
else
sb.append((char)num);
}
if(sb.length() != 0)
return sb.toString();
return null;
}
public void serMyLineNumber(int lineNumber)
{
this.lineNumber = lineNumber;
}
public int getMyLineNumber()
{
return lineNumber;
}
public void myClose() throws IOException
{
r.close();
}
}
class MyLineNumberReaderDemo
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("PersonDemo.java");
MyLineNumberReader mynr = new MyLineNumberReader(fr);
String line = null;
mynr.serMyLineNumber(100);
while((line = mynr.myReadLine()) != null)
{
System.out.println(mynr.getMyLineNumber()+".."+line);
}
mynr.myClose();
}
}