------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
一、IO流概述
IO(Input,Output)流:用来处理设备之间的数据传输。
1,java对数据的操作是通过流的方式。
2,java用于操作流的对象都在IO包中。
3,流按操作的数据可以分为两种:字节流和字符流。
4,流按照流向可以分为:输入流和输出流。
字节流的抽象基类:InputStream和OutputStream
字符流的抽象基类:Reader和Writer
注意:由着四个类派生出来的子类名称都是以其父类名作为子类名的后缀的。如:InputStream的子类FileInputStream,Reader的子类FileReader。
二、字符流
1,FileWriter:字符流中Writer的子类。
package 博客8_IO流一;
import java.io.FileWriter;
import java.io.IOException;
public class IO流
{
public static void main(String[] args)throws IOException
{
/*
* 创建FileWriter对象,该对象一初始化就必须明确被操作的文件。
* 而且,该文件会被创建到指定目录下,如果该目录下已经有了同名文件,则会被覆盖。
* */
FileWriter fw = new FileWriter("IO.txt");
//调用FileWriter里的write方法,将字符串写入流中。
fw.write("lalala");
//刷新流对象中缓冲的数据,将数据刷新到目的地。
fw.flush();
//关闭资源,但是关闭之前会刷新一次流对象缓冲区中的资源。
fw.close();
}
}
close和flush的区别:flush刷新后,流可以继续使用。close关闭后,流也将关闭,如果再操作流,则编译不能通过。
2,对IOException的处理方式:
public class IOException处理 {
public static void main(String[] args) {
FileWriter fw = null;//try外建立引用,try里建对象。
try {
fw = new FileWriter("IOException.txt");
fw.write("hahahaha");
} catch (IOException e) {
e.printStackTrace();
}
finally
{
try {
if(fw!=null)//否则会出现空指针异常。
fw.close();//必须要关闭资源,所以close应放在finally里。
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3,文件的续写:传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处续写。
package 博客8_IO流一;
import java.io.FileWriter;
import java.io.IOException;
public class 文件的续写Demo
{
public static void main(String[] args)throws IOException
{
FileWriter fw = new FileWriter("IO.txt",true);
fw.write("hiehiehie");。
fw.close();
}
}
注意:window里的换行是用\r\n共同完成的。
4,文件的读取:
a:当FileReader里的read方法读取到文件的最后一个字符时,会return-1,所以可以依此作为循环结束的条件来达到循环读取的目的。
package 博客8_IO流一;
import java.io.FileReader;
import java.io.IOException;
public class 文件读取 {
/**
* @param args
*/
public static void main(String[] args)throws IOException {
// TODO Auto-generated method stub
FileReader fr = new FileReader("IO.txt");
int ch = 0;
while((ch=fr.read())!=-1)
System.out.println((char)ch);
fr.close();
}
}
b:通过字符数组的方式读取数据。
package 博客8_IO流一;
import java.io.FileReader;
import java.io.IOException;
public class 文件读取方式2 {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
FileReader fr = new FileReader("IO.txt");
char [] buf = new char[1024];
int num = 0;
while((num=fr.read(buf))!=-1)
<span style="white-space:pre"> </span>System.out.println(num+"...."+new String(buf,0,num));
fr.close();
}
}
5,文件拷贝。
package 博客8_IO流一;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class 文件拷贝Text {
/**
* 需求,文件的拷贝。
*/
public static void main(String[] args)//throws IOException
{
// TODO Auto-generated method stub
//copy_1();
copy_2();
}
public static void copy_2() {
//通过数组形式进行文件的拷贝。
FileWriter fw=null;//在外面建立引用,在里面获取对象
try {
fw = new FileWriter("IO_copy.txt");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileReader fr=null;
try {
fr = new FileReader("IO.txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
char [] buf=new char[1024];//定义1024或其整数倍的数组
int num = 0;
try {
while((num=fr.read(buf))!=-1)
{
fw.write(buf, 0, num);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
if(fw!=null)
try {
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(fr!=null)
try {
fr.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void copy_1()throws IOException {
// TODO Auto-generated method stub
FileWriter fw = new FileWriter("IO_copy.txt");
FileReader fr = new FileReader("IO.txt");
int ch = 0;
while((ch=fr.read())!=-1)
{
fw.write(ch);
}
fr.close();
fw.close();
}
}
三、字符流缓冲区
缓冲区的意义:缓冲区的出现提高了对数据的读写效率。
字符流缓冲区对应的类:BufferedWriter,BufferedReader。
注意:缓冲区要结合流才可以使用,在流的基础上对流的功能进行了增强。
package 博客8_IO流一;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class 字符流缓冲区Demo {
public static void main(String[] args)throws IOException {
// TODO Auto-generated method stub
FileWriter fw = new FileWriter("缓冲区练习.txt");
BufferedWriter bufw = new BufferedWriter(fw);
for(int x = 0 ;x<5;x++)
{
bufw.write("abcdse");
bufw.flush();
bufw.newLine();
}
bufw.close();
}
}
readLine方法的原理:无论是读一行还是读取多个字符,最终都是在硬盘上一个一个的读取。所以使用的还是read中一次读一个的方法。
自定义缓冲区代码示例:
package 博客8_IO流一;
import java.io.*;
class MyBufferedReader
{
private FileReader r;
MyBufferedReader(FileReader r)
{
this.r=r;
}
public String MyReadLine()throws IOException
{
StringBuilder sb = new StringBuilder();//定义一个容器作为存放数据的缓冲区
int ch = 0 ;
while((ch=r.read())!=-1)
{
if(ch=='\r')//如果读到\r,那么不确定是否是这一行的结尾,所以要继续往下读
continue;
if(ch=='\n')//读到\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();
}
}
public class 自定义缓冲区_MyBufferedReader
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("缓冲区练习.txt");
MyBufferedReader bufr = new MyBufferedReader(fr);
String line =null;
while((line=bufr.MyReadLine())!=null)
System.out.println(line);
bufr.myClose();
}
}
四、装饰设计模式及LineNumberReader装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,那么自定义的该类就称为装饰类。
装饰类通常会通过构造方法接收被装饰的对象,并基于被装饰对象的功能,提供更强的功能。
装饰设计模式比继承要灵活,避免了继承体系臃肿,且降低了类与类之间的耦合性。
自定义MyLineNumbeReader代码如下:
package 博客8_IO流一;
import java.io.*;
class MyLineNumberReaderMethod//定义自己的装饰类,可以在读取的时候添加行号。
{
private Reader r;
private int lineNumber;
MyLineNumberReaderMethod(Reader r)
{
this.r=r;
}
public String MyReadLine() throws IOException//自定义ReadLine方法
{
lineNumber++;//当方法被调用的时候,就让行号计数器+1
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 setLineNumber(int lineNumber)
{
this.lineNumber=lineNumber;
}
public int getLineNumber()
{
return lineNumber;
}
public void MyClose() throws IOException
{
r.close();
}
}
public class MyLineNumberReader
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("HashSetDemo.java");
MyLineNumberReaderMethod mlrm = new MyLineNumberReaderMethod(fr);
String line = null;
mlrm.setLineNumber(100);
while((line=mlrm.MyReadLine())!=null)
{
System.out.println(mlrm.getLineNumber()+"::"+line);
}
mlrm.MyClose();
}
}
由于之前已经做过了MyBufferedReader修饰类,所以可以让MyLineNumberReaderMethod继承
MyBufferedReaderr即可,代码优化后如下:
class MyLineNumberReaderMethod extends MyBufferedReader
{
private int lineNumber;
MyLineNumberReaderMethod(Reader r)
{
super(r);
}
public String MyReadLine() throws IOException//自定义ReadLine方法
{
lineNumber++;//当方法被调用的时候,就让行号计数器+1
return super.MyReadLine();
}
public void setLineNumber(int lineNumber)
{
this.lineNumber=lineNumber;
}
public int getLineNumber()
{
return lineNumber;
}
}
public class MyLineNumberReader
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("HashSetDemo.java");
MyLineNumberReaderMethod mlrm = new MyLineNumberReaderMethod(fr);
String line = null;
mlrm.setLineNumber(100);
while((line=mlrm.MyReadLine())!=null)
{
System.out.println(mlrm.getLineNumber()+"::"+line);
}
mlrm.myClose();
}
}