转自:http://blog.csdn.net/johnny901114/article/details/8710403

一、BufferWriter类
IO的缓冲区的存在就是为了提高效率,把要操作的数据放进缓冲区,然后一次性把缓冲区的内容写到目的地,而不是写一次就往目的地写一次.
在这里要注意的是当我们关闭了缓冲区对象实际也关闭了与缓冲区关联的流对象。
BufferWriter
try {
  FileWriter fw =new FileWriter("test.txt");
  //使用缓冲区必须要与一个流对象相关联
  BufferedWriter bw =new BufferedWriter(fw);
  bw.write("hello world!");
  //使用缓冲区的时候要注意刷新

  bw.flush();

  //关闭缓冲区的对象,实际上是关闭与它关联的流对象最好放在finally执行
  bw.close();
 
catch (IOException e) {
  e.printStackTrace();
}

其实BufferReader也是差不多的,这里就不多讲

FileReader fr =new FileReader("test.txt");
BufferedReader br =new BufferedReader(fr);
String line =null;
//注意readLine方法读取的内容不包括换行符
while((line=br.readLine())!=null){
System.out.println(line);
}
readLine原理:
无论是读一行,获取多个字符,最终都是在硬盘上一个一个读取,所以最终使用的还是read方法一次读一个的方法。
 
二、装饰模式
package i18n;

public class test {

}

class Person {
public void eat() {
System.out.println("吃饭");
}
} public class PersonEnhance {
private Person p; // 把需要增强 的类传进去初始化
public PersonEnhance(Person p) {
this.p = p;
} public void enhanceEat() {
System.out.println("开胃酒");
p.eat();
System.out.println("甜点");
}
}
装饰模式作用:就是在原有类的基础上把某个方法增强功能 
但是这让我想到了java 的动态代理,他也是在某个方法的基础上增加额外的功能,那么她们有什么区别呢? 
装饰类和被装饰的类是应该继承或实现相同的接口,而java的动态代理不是,
还有一个不同点就是动态代理可以横切多个面,也就是同时对多个方法进行增强.
 
通过装饰模式和继承的区别发现了程序设计之美,虽然继承也可以增强某个方法,但是它使得类的体系很臃肿,并且可扩展性不好
因为装饰模式中,我们可以把被装饰类的父类当作参数传进装饰类的构造方法内,那么你这一个装饰类就可以应用于这个体系的了,这也是java多态性的好处.
相比较之下使用装饰模式降低了类之间的关系.
装饰类是因为增强了已有的对象,具有的功能和已有的是相同的,是不过提供了更强的功能,所以装饰类和被装饰类通常属于一个体系中的.
 
在API中可以看到BufferedReader类还有一个子类LineNumberReader

通过API对得知,这是一个字符缓冲输出流,该类保持对行号的跟踪,可以通过该类的setLineNumber(int) andgetLineNumber() 方法分别设置获取行号
例如程序:
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("test.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String num = null;
while ((num = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + num);
}
}

控制台输出:  

但是我们也可以改变行号的开始值
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("test.txt");
LineNumberReader lnr = new LineNumberReader(fr);
String num = null;
// 设置行号的开始值为100
lnr.setLineNumber(100);
while ((num = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + num);
} }

输出结果为:  

LineNumberReader
EnhanceLineNumberReader
public String readLine() throws IOException {
int lineNumber=0;
lineNumber++;
StringBuilder buffer =new StringBuilder();
int i = 0;
while ((i =reader.read()) != -1) {
if ((char) i =='\r') {
continue;
}
if ((char) i =='\n') {
return buffer.toString();
}else {
buffer.append((char) i);
}
}
if (buffer.length() != 0) {
return buffer.toString();
}
return null;
}
书出结果是一样的
下面开始学习字节流
通过API文档字节流的顶级类为InputStream和OutputStream
首先来看一下FileOutputStream和FileInputStream
public static void writeData()throws Exception{
OutputStream out =new FileOutputStream("D:\\test2.txt");
out.write("hello inputStream!".getBytes());
}
执行上面代码后,发现在D盘创建了test2.txt文件并且内容是hello inputStream!
从上面可以看出这和字符流是有区别的,因为当我们在使用字符流的时候,如果没有刷新并且没有关闭那么文件内容是空的,而这里刚好相反.
但是最好我们还是调用close方法,关闭资源.提高性能.
 
下面实现读取操作:
public static void readData() throws Exception {
InputStream is = new FileInputStream("D:\\test2.txt");
int num = 0;
while ((num = is.read()) != -1) {
System.out.println((char) num);
}
}

但是这样效率比较低,因为读取一次写一次,我们可以使用缓冲:  

public static void readData2()throws Exception {
InputStream is =new FileInputStream("D:\\test2.txt");
int num = 0;
byte[] buffer =newbyte[1024];
//把读取到的数据放进字节数组里面
while ((num = is.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, num));
}
}

在InputStream类中有这样一个方法available()返回int 他的作用是返回文件内容的长度 那么我们就可以这样读取数据,而不用while循环了  

public static void readData3()throws Exception {
InputStream is =new FileInputStream("D:\\test2.txt");
//返回文件的长度
int num = is.available();
把字节数组的长度定义成文件长度,那么这个数组就刚好装下这个文件了
byte[] buffer =newbyte[num];
is.read(buffer);
System.out.println(new String(buffer));
}
但是这样有一个缺陷,如果一个文件非常大,那么这就会出现内存溢出了.所以这是用操作小型 的文件.
练习,复制一份图片:代码片段:

InputStream is = new FileInputStream("D:\\imagetest\\desk.jpg");
OutputStream os = new FileOutputStream("E:\\desk1.jpg");
byte[] buffer = new byte[1024];
int readNum = 0;
int a=0;
while((readNum=is.read(buffer))!=-1){
System.out.println(a++);
os.write(buffer, 0, readNum);
}

使用java缓冲输出流  

BufferedOutputStream buffOs =new BufferedOutputStream(new FileOutputStream("F:\\KuGou\\baby2 - baby one more time.mp3"));
BufferedInputStream buffIs =new BufferedInputStream(new FileInputStream("F:\\KuGou\\baby - baby one more time.mp3"));
int len = 0;
while((len=buffIs.read())!=-1){
buffOs.write(len);
}
buffOs.close();
buffIs.close();
获取键盘录入:
System.out对应的是标准的输出设备一般指控制台
System.in对应的是标准输入设备:键盘
下面模拟一个键盘录入的功能:
public static void main(String[] args) throws IOException {
InputStream is = System.in;
StringBuilder buffer = new StringBuilder();
int i = 0;
while (true) {
i = is.read();
if ('\r' == i)
continue;
if ('\n' == i) {
String value = buffer.toString();
// 如果录入的是over那么则退出
if ("over".equals(buffer.toString()))
break;
System.out.println(value);
// 清空缓冲区 以免下次录入时不会和前面录入的汇合
buffer.delete(0, buffer.length());
} else {
buffer.append((char) i);
}
}
}
注意在输入流在读取数据的时候连回车也会读取的.在windows中\r\n代表换行 例如下面简单的程序
InputStream is = System.in;
System.out.println(is.read());

System.out.println(is.read());

控制台输出:
13
10
对于键盘录入功能我们可以使用更加简单的方式:因为他这个功能实际上就是读取一行 的操作:
那么就可以考虑使用readLine方法,然后该方法是字符六BufferedReader的方法
然而InputStream又是字节流.那么怎么办呢?
我们可以使用InputStreamReader类,这个类是字节流到字符流的桥梁,
public static void main(String[] args) throws IOException {
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if (line.equals("over")) {
break;
}
System.out.println(line.toUpperCase());
}
}

对应的OutputStreamWriter是字符流向字节流转换的桥梁 也就是读进来的是字符,写进去的是字节,在上面的基础上我们可以这样改写:  

public static void main(String[] args) throws IOException {
InputStream is = System.in;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
BufferedWriter bw = new BufferedWriter(osw);
String line = null;
while ((line = br.readLine()) != null) {
if (line.equals("over")) {
break;
}
bw.write(line);
// 注意使用字符流要注意flush
bw.flush();
// System.out.println(line.toUpperCase());
}
}
但是控制台输出为:

发现输出的数据没有换行
当然我们可以在line后面加上\r\n
但是这是不跨品台的
我们可以这样解决:
我们可以使用
BufferedWriter 的newLine方法
在bw.write(line);后面加上bw.newLine(); 即可
总结: 下面总结一下IO的操作规律:
1,明确源和目的:
    源 :输入流,InputStream  Reader
    目的: 输入流 OutpuStream Writer
3当明确体系后,在明确使用哪个具体的对象
    通过设备来进行区分:
        源设备:  存 硬盘 键盘
        目的设备:  内存  硬盘 控制台

  

  

  

  

  

  

  

  

Java I/O流操作(二)---缓冲流[转]的更多相关文章

  1. JAVA基础复习与总结<八> 缓冲流_数据流_对象流_IO总结

    缓冲流.数据流以及对象流 一.缓冲流 缓冲流的概念:在读写的时候,对于单字节的读取会造成硬盘的频繁读写,增加访问次数,降低了读取文件的效率.而引入缓冲流之后,就可以将多个字节写入缓冲区,在缓冲区积累之 ...

  2. Java IO流之【缓冲流和文件流复制文件对比】

    与文件流相比,缓冲流复制文件更快 代码: package Homework; import java.io.BufferedOutputStream; import java.io.File; imp ...

  3. 使用文件流与使用缓冲流完成文件的复制操作性能对比,文件流 FileInputStream FileOutputStream 缓冲流: BufferedInputStream BufferedOutputStream

    package seday06; import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOExc ...

  4. File类与常用IO流第八章——缓冲流

    第八章.缓冲流 缓冲流概述 缓冲流,也叫高效流,是对4个基本的FileXxx流的增强.按照数据类型分为4类:   输入缓冲流 输出缓冲流 字节缓冲流 BufferedInputStream Buffe ...

  5. JAVA基础学习day20--IO流二-缓冲流、字节流

    一.缓冲流 1.1.字符流的缓冲区 缓冲区的出现是为了提高IO的读写效率 对应类 BufferedReader BufferedWriter 缓冲区要结合流才可以使用 在流的基础上对流的功能进行了增强 ...

  6. java写文件读写操作(IO流,字节流)

    package copyfile; import java.io.*; public class copy { public static void main(String[] args) throw ...

  7. Java IO流之字符缓冲流

    字符流: 1.加入字符缓存流,增强读取功能(readLine) 2.更高效的读取数据 BufferedReader 从字符输入流读取文本,缓冲各个字符,从而实现字符.数组和行的高效读取. FileRe ...

  8. java IO流之三 使用缓冲流来读写文件

    原文:http://blog.csdn.net/haluoluo211/article/details/52183219 一.通过BufferedReader和BufferedWriter来读写文件 ...

  9. Java - IO System类支持和缓冲流

    System类的支持和缓冲流 System类对IO的支持 在System类中,为了支持IO操作提供了三个常量: 错误输出: public static final PrintStream err; 输 ...

随机推荐

  1. hdu 5115 Dire Wolf(区间dp)

    Problem Description Dire wolves, also known as Dark wolves, are extraordinarily large and powerful w ...

  2. 使用过渡场景在多个场景的切换COCOS2D(4)

    CCNode有三个方法,使用CCDirector的replaceScene方法替换场景时,每个节点都会调用这三个方法: onEnter与onExit方法在改变场景过程中的特定时刻被调用,这取决于是否使 ...

  3. 《github一天一道算法题》:插入排序

    看书.思考.写代码! /*********************************************** * copyright@hustyangju * blog: http://bl ...

  4. zepto打造一款移动端划屏插件

    效果图 样式1 样式2 调用 正常情况下应该是后台生成的html代码,但还是写了一套操作tab页的方法 调用简便如下: <link rel="stylesheet" href ...

  5. wcf 速成,转的啊 第一天

    作为WCF速成系列,只介绍些项目开发中常用到的实战知识. 学习wcf,还是对其中的几个术语要了解一下.wcf中有一个ABC的概念,就是 第一: "A" 是地址,就是告诉别人我wcf ...

  6. rem vh vw vmin vmax ex ch

    rem 我们首先介绍下和我们熟悉的很相似的货.em 被定义为相对于当前对象内文本的字体大小.如果你给body小哥设置了font-size字体大小,那么body小哥的任何子元素的1em就是等于body设 ...

  7. 关于新装ubuntu系统update失败和build-essential失败的解决办法

    我是12月4日在新电脑上的vmware-workstation 10 上安装的ubuntu14.04LTS,但安装后再校园环境下总是build-essential失败,上网一查,说是要先update, ...

  8. java通过JNI接口调用C语言-初级

    JNI(java native interface):即java本地调用C的接口. 先看整体运行: 下面是过程: #vim test.java public class test{ public na ...

  9. iphone:自定义UIAlertView

    由于项目中有这样一个需求:需要在保存是弹出框选择保存的地点.选择UIAlertView来实现,但是要在UIAlertView中增加UISwitch的控件,这就需要自定义一个继承UIAlertView的 ...

  10. 用不动点组合子解递归(python实现)

    不动点组合子 Y = λf. (λx. f (x x)) (λx. f (x x)) θ = (λx. λy. (y(x x y))) (λx.λy.(y(x x y))) Y f = f (Y f) ...