概述:IO就是java中的输入和输出,主要是对数据的操作。Java中把这些输入和输出的内容看作流来处理,根据处理的对象的不同,分为字符流和字节流。,根据流向不同可分为输入流和输出流。
字符流:由连续的char组成的流,适用于多个自己表示一个字符的内容,例如文本数据。
字符流就是字节流读取字节数据后,先查相应的码表,获取对应的文字然后再进行输出。
字节流:连续的byte组成的流。适用于字节表示的内容,例如:多媒体文件,图片等。
字节流和字符流的区别:
1,字节流读取的时候,读到一个字节就返回一个字节。
字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在UTF-8码表中是3个字节)时。先去查指定的编码表,将查到的字符返回。
2,字节流可以处理所有类型数据,如图片,mp3,avi。
而字符流只能处理字符数据。
字符流的抽象基类:
Reader(读)、Writer(写)
字节流的抽象基类:
InputStream(读入)、OutputStream(输出)
这里所谓的读写,输入和输出都是相对的概念,都是相对于程序本身而言的,把硬盘上的数据读入到内存,就叫输入或读入,把程序中的数据输出到硬盘或者网络,就叫输出。
字符输入流:
Reader :抽象基类,没有构造方法。有以下几个常用的方法:
1、Int read()返回以一个用int表示的char,-1表示到文件末尾。
2、Int read(char[] a)把从流中得到的多个字符放入char[]中,并返回实际得到的字符数,-1表示到流的末尾。
3、void close()关闭字符流,关闭之前会调用flush()方法,刷新缓冲区。
要从一个
FileReader:文件输入流。用于读取文本文件或者关联文本文件。
构造函数:FileReader(String)和FileReader()两个构造方法。在读取流对象初始化的时候,必须要指定一个被读取的文件。如果该文件不存在会发生FileNotFoundException.
从一个流得到单个字符进行输入时,大致步骤如下:
1、 创建字符流对象r,指明从哪里输入。
2、 int c = 0;
while(true){
c = r.read();//得到流中的内容
if(c==-1)//判断是否结束
break;
对c中的得到的内容进行处理
}
3、 关闭流
以上的while循环通畅简化为:
While((c==in.read())!=-1)
{
处理c;
}
从一个流得到多个字符进行输入时,大致步骤如下:
1、 创建字符流对象r,指明从哪里输入
2、 char [] c= new char[1024];//指定缓冲区大小
int len = 0;//接受读取的字符数
while(true){
len=r.read(c);//得到流中的内容
if(len==-1)//判断是否结束
break;
对c中的得到的内容进行处理
}
3、 关闭流
以上的while循环通畅简化为:
While((len==in.read(c))!=-1)
{
处理c;
}
注意:1、一次读取多个字节比一次读取一个字节效率高。
2、对于读取或者写入流对象的构造函数,以及读写方法,还有刷新关闭功能都会抛出IOException或者其子类。所以都要进行处理。或者throws抛出,或者try catch处理。
package IOTest;
import java.io.*;
public class FileReaderDemo {
public static void main(String[] args) throws IOException{
FileReaderDemo demo = new FileReaderDemo();
demo.readFile("miss.txt");
}
public static void readFile(String fileName)throws IOException
{
Reader r = null;
try{
r = new FileReader(fileName);//指定从哪里输入
char[]c = new char[1024];
int len = 0;
while((len = r.read(c))!=-1)//得到流的内容并判断是都到流的末尾
{
System.out.println(new String(c,0,len));//对得到的内容进行处理
}
}finally
{
if(r!=null)
r.close();
}
}
}
BufferedReader:缓冲字符流
缓冲区的出现提高了对流的操作效率。原理:其实就是将数组进行封装,将每次读入数据先从封装的缓冲区读,如果没有则从被套接的流中读入多个字符放入到缓冲数组中。
两个构造方法:
BufferedReader(Reader r) 指定套接的输入流。
BufferedReader(Reader r,int n)指定套接的输入流,用int 指定缓冲区的大小。
特殊方法:
String readLine()一次可以得到文件中的一行,不过得到的是去掉换行符之后的内容。当返回null时表示到流的末尾。
实例代码如下:
package IOTest;
import java.io.*;
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
BufferedReaderDemo demo = new BufferedReaderDemo();
demo.readFile("miss.txt");
}
public static void readFile(String fileName) throws IOException
{
BufferedReader br = null;
try{
br = new BufferedReader(new FileReader(fileName),1024);//指明从哪里输入
String line= null;
while((line = br.readLine())!=null)//得到流并判断是否到流的末尾
{
System.out.println(line);//对得到的内容进行处理
}
}finally
{
if(br!=null)
br.close();//关闭流
}
}
}
字符输出流:
Writer:抽象基类,没有构造方法。有以下几个常用的方法:
1,write(ch):将一个字符写入到流中。
2,write(char[]):将一个字符数组写入到流中。
3,write(String):将一个字符串写入到流中。
4,flush():刷新流,将流中的数据刷新到目的地中,流还存在。
5,close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭。
FileWriter:
该类没有特有的方法。只有自己的构造函数。
该类特点在于,
1,用于处理文本文件。
2,该类中有默认的编码表,
3,该类中有临时缓冲。
构造函数:在写入流对象初始化时,必须要有一个存储数据的目的地。
FileWriter(Stringfilename):
该构造函数做了什么事情呢?
1,调用系统资源。
2,在指定位置,创建一个文件。
注意:如果该文件已存在,将会被覆盖。
FileWriter(Stringfilename,boolean append): 该构造函数:当传入的boolean类型值为true时,会在指定文件末尾处进行数据的续写。
BufferedWriter:该类套接在其他输出流上,提供缓冲功能。
两个构造方法:
BufferedWriter(Writerw):指定需要套接的流。
BufferedWriter(Writerw,int n):n用于之指定缓冲区的大小。
特有方法:
newLine():跨平台的换行符。
练习:通过缓冲区的形式,对文本文件进行拷贝。
public static void main(String[] args)
{
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
String line = null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
bufw.close();
bufr.close();
}
readLine():方法的原理:
其实缓冲区中的该方法,用的还是与缓冲区关联的流对象的read方法。
只不过,每一次读到一个字符,先不进行具体操作,先进行临时存储。
当读取到回车标记时,将临时容器中存储的数据一次性返回。
实现自己的BufferedReader:
class MyBufferedReader
{
private Reader r;
MyBufferedReader(Reader r)
{
this.r = r;
}
public String myReadLine()throws IOException
{
//1,创建临时容器。
StringBuilder sb = new StringBuilder();
//2,循环的使用read方法不断读取字符。
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();
}
}
装饰设计模式:
装饰设计模式:对一组对象的功能进行增强时,就可以使用该模式进行问题的解决。
装饰和继承都能实现一样的特点:进行功能的扩展增强,但是装饰比继承灵活,装饰的特点:装饰类和被装饰类都必须所属同一个接口或者父类。
该模式和继承有什么区别呢?
它比继承有更好的灵活性。通常装饰类和被装饰类都同属与一个父类或者接口。
举例:
Writer:(注:不要误解,以下两个对象不存在,只为举例。)
|--MediaWriter
|--BufferedMediaWriter
|--TextWriter
|--BufferedTextWriter
当Writer中子类对象过多,那么为了提高每一个对象效率,每一个对象都有一个自己的子类Buffered。
虽然可以实现,但是继承体系变的很臃肿。
其实子类都是在使用缓冲技术。可以对缓冲技术进行描述,将需要增强的对象传递给缓冲区即可。这就是多态,提高了程序的扩展性。
同时BufferedWriter中一样具体write方法,只不过是增强后的write。
所以BuferedWriter也应该是Writer中的一个子类。
class BufferedWriter extends Writer
{
private Writer w;
BufferedWriter(Writer w)
{
this.w = w;
}
}
这就是装饰设计模式。