字节流的两个基类:

  1. InputStream
  2. OutputStream

字符流的两个基类:

  1. Reader
  2. Writer

Writer

先学习一下字符流的特点。

既然IO流是用于操作数据的,那么数据的最常见体现形式是:文件。那么先以操作文件为主来演示。

例,需求:在硬盘上,创建一个文件并写入一些文字数据。

分析:

找到一个专门用于操作文件的Writer子类对象——FileWriter,后缀名是父类名,前缀名是该流对象的功能。

步骤:

  1. 创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。其实该步骤就是在明确数据要存放的目的地。
  2. 调用write(),将字符串写入到流中。
  3. 刷新流对象中的缓冲区中的数据,将数据刷到目的地中。
  4. 关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。将数据刷到目的地中。和flush()区别:flush刷新后,流可以继续使用,close()刷新后,会将流关闭。

示例代码如下:

import java.io.FileWriter;
import java.io.IOException; public class FileWriterDemo0 { public static void main(String[] args) throws IOException {
//创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件
//而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步骤就是在明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt"); //调用write(),将字符串写入到流中
fw.write("abcde"); //刷新流对象中的缓冲区中的数据,将数据刷到目的地中。
//fw.flush(); /*
* 关闭流资源,但是关闭之前会刷新一次内部的缓冲区中的数据。
* 将数据刷到目的地中。
* 和flush()区别:flush刷新后,流可以继续使用,close()刷新后,会将流关闭。
*/
fw.close(); fw.write("haha");
} }

IO异常的处理方式:

示例代码:

/*
IO异常的处理方式。
最后无论如何都应关闭资源,所以应放在finally代码块中
*/
import java.io.FileWriter;
import java.io.IOException; public class FileWriterDemo1 { public static void main(String[] args) {
FileWriter fw = null;
try {
fw = new FileWriter("demo.txt");
fw.write("abcdefg");
} catch (IOException e) {
System.out.println("catch:" + e.toString());
} finally {
try {
if(fw != null)
fw.close();
} catch (IOException e) {
System.out.println(e.toString());
}
} } }

对已有文件的数据续写:

示例代码:

/*
演示对已有文件的数据续写。
*/
import java.io.FileWriter;
import java.io.IOException; public class FileWriterDemo2 { public static void main(String[] args) throws IOException {
/*
* 传递一个true参数,代表不覆盖已有的文件。
* 并在已有文件的末尾处进行数据续写。
* \r\n在windows中表示行终止符
*/
FileWriter fw = new FileWriter("demo.txt", true); fw.write("nihao\r\nxiexie"); fw.close();
} }

Reader

例,需求:从硬盘的一个文件中读取内容

代码:

import java.io.FileReader;
import java.io.IOException; public class FileReaderDemo0 { public static void main(String[] args) throws IOException {
/*
* 创建一个文件读取流对象,和指定名称的文件相关联。
* 要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException。
*/
FileReader fr = new FileReader("demo.txt"); /*
* 调用读取流对象的read()
* read():一次读取一个字符,会自动往下读。
*/
int ch = 0;
while((ch = fr.read()) != -1) {
System.out.println((char)ch);
}
/*
while(true) {
int ch = fr.read();
if(ch == -1)
break;
System.out.println("ch = " + (char) ch);
}
*/ fr.close();
} }

图示:

第二种方式:通过字符数组进行读取。

示例代码如下:

/*
第二种方式:通过字符数组进行读取。
*/
import java.io.FileReader;
import java.io.IOException; public class FileReaderDemo1 { public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("demo.txt"); /*
* 定义一个字符数组,用于存储读到的字符
* 该read(char[])返回的是读到的字符个数。
*/
char[] buf = new char[1024];//字符数组大小为2KB int num = 0;
while((num = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, num));
} fr.close();
} }

图示:

练习:读取一个.java文件,并打印在控制台上。

代码如下:

import java.io.FileReader;
import java.io.IOException; public class FileReaderTest { public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("FileWriterDemo2.java"); char[] buf = new char[1024]; int num = 0; while((num = fr.read(buf)) != -1) {
System.out.println(new String(buf, 0, num));
} fr.close();
} }

字符流缓冲区

缓冲区的出现是为了提高流的操作效率而出现的,所以在创建缓冲区之前,必须要先有流对象。

   BufferedWriter

该缓冲区中提供了一个跨平台的换行符:newLine()。

示例代码如下:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException; public class BufferedWriterDemo { public static void main(String[] args) throws IOException {
/*
* 创建一个字符写入流对象
*/
FileWriter fw = new FileWriter("buf.txt");
/*
* 为了提高字符写入流的效率,加入了缓冲区。
* 只要将需要被提高效率的流对象作为参数,传递给缓冲区的构造函数即可。
*/
BufferedWriter bufw = new BufferedWriter(fw); for(int i = 0; i < 5; i++) {
bufw.write("abcde" + i);
bufw.newLine();//bufw.write("\r\n")
bufw.flush();//写一次刷新一次。
}
/*
* 记住,只要用到缓冲区,就要刷新。
*/
//bufw.flush(); /*
* 其实关闭缓冲区,就是在关闭缓冲区中的流对象。
* 所以fw.close();就不用写了。
*/
bufw.close(); //fw.close();
} }

BufferedReader

字符读取流缓冲区,该缓冲区提供了一个一次读一行的方法:readLine(),方便于对文本数据的获取。当返回null时,表示读取到文件末尾。

readLine()方法返回的时候只返回回车符之前的数据内容,并不返回回车符(行终止符)。

示例代码:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException; public class BufferedReaderDemo0 { public static void main(String[] args) throws IOException {
/*
* 创建一个读取流对象和文件相关联
*/
FileReader fr = new FileReader("buf.txt"); /*
* 为了提高效率,加入缓冲技术,将字符读取流对象作为参数传递给缓冲区对象的构造函数
*/
BufferedReader bufr = new BufferedReader(fr); String line = null; while((line = bufr.readLine()) != null) {
System.out.print(line);
} bufr.close();
} }

需求:明白了BufferReader类中特有方法readLine()的原理后,可以自定义一个类中包含一个功能和readLine()一致的方法,来模拟一下BufferReader。

示例代码如下:

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader; class MyBufferReader extends Reader {
/*
private FileReader fr = null; MyBufferReader(FileReader fr) {
this.fr = fr;
}
*/ private Reader fr = null; MyBufferReader(Reader fr) {
this.fr = fr;
} /*
* 可以一次读一行数据的方法
*/
public String myReadLine() throws IOException {
/*
* 定义一个临时容器,原BufferReader封装的是一个字符数组
* 为了演示方便,定义一个StringBuilder容器,因为最终还是要将数据变为字符串。
*/
StringBuilder sb = new StringBuilder();
int ch = 0;
while((ch = fr.read()) != -1) {
if(ch == '\r')
continue;
if(ch == '\n')
return sb.toString();
else
sb.append((char) ch);
}
if(sb.length() != 0) {//如果文本数据最后的行终止符故意去掉,那么StringBuilder里面还是有数据的 ,也要给予返回
return sb.toString();
}
return null;//如果已到达流末尾,则返回 null
} /*
* 覆盖Reader类中的抽象方法。
*/
@Override
public void close() throws IOException {
fr.close();
} @Override
public int read(char[] cbuf, int off, int len) throws IOException {
return fr.read(cbuf, off, len);
} public void myClose() throws IOException {
fr.close();
} }
public class MyBufferReaderDemo { public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("buf.txt"); MyBufferReader myBuf = new MyBufferReader(fr); String line = null; while((line = myBuf.myReadLine()) != null) {
System.out.println(line);
} myBuf.myClose();
} }

LineNumberReader

一个带行号的缓冲区。

示例代码如下:

import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader; public class LineNumberReaderDemo { public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("PersonDemo.java"); LineNumberReader lnr = new LineNumberReader(fr); String line = null; lnr.setLineNumber(100);//设置行号从100开始,实际打印是从101开始的 while((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + " " + line);
} lnr.close();
} }

练习:模拟一个带行号的缓冲区对象。

代码:

import java.io.FileReader;
import java.io.IOException;
import java.io.Reader; class MyLineNumberReader extends MyBufferReader {
private int lineNumber;//行号 MyLineNumberReader(Reader r) {
super(r);
} public String myReadLine() throws IOException { lineNumber++;//myReadLine()方法读一次自增一次 return super.myReadLine();
} public int getLineNumber() {
return lineNumber;
} public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
} }
/*
class MyLineNumberReader {
private Reader r;
private int lineNumber;//行号 MyLineNumberReader(Reader r) {
this.r = r;
} public String myReadLine() throws IOException { lineNumber++;//myReadLine()方法读一次自增一次 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 int getLineNumber() {
return lineNumber;
} public void setLineNumber(int lineNumber) {
this.lineNumber = lineNumber;
} public void myClose() throws IOException {
r.close();
} }
*/
public class MyLineNumberReaderDemo { public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("bufWriter_Copy.txt"); MyLineNumberReader my = new MyLineNumberReader(fr); String line = null; //my.setLineNumber(100); while((line = my.myReadLine()) != null) {
System.out.println(my.getLineNumber()+ " " +line);
} my.myClose();
} }

由此引出装饰设计模式

装饰设计模式:当想要对已有的对象进行功能增强时,可以定义类,将已有对象传入,基于已有的功能,并提供加强功能。那么自定义的该类称为装饰类。

装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。

举例说之:

class Person {
public void chifan() {
System.out.println("吃饭");
}
} class SuperPerson {
private Person p = null;
SuperPerson(Person p) {
this.p = p;
}
public void superChifan() {
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
System.out.println("来一根");
}
} public class PersonDemo { public static void main(String[] args) {
Person p = new Person(); //p.chifan(); SuperPerson sp = new SuperPerson(p);
sp.superChifan();
} }

装饰模式与继承之间的区别

通过以下分析:

MyReader//专门用于读取数据的类。
|---MyTextReader
|---MyBufferTextReader
|---MyMediaReader
|---MyBufferMediaReader
|---MyDataReader
|---MyBufferDataReader //该类扩展性很差,找到其参数的共同类型,通过多态的形式,可以提高扩展性
class MyBufferReader { MyBufferReader(MyTextReader text) { } MyBufferReader(MyMediaReader media) { }
}
------------------------------------------------------------------
class MyBufferReader extends MyReader {
private MyReader r;
MyBufferReader(MyReader r) { } }
MyReader//专门用于读取数据的类。
|---MyTextReader(被装饰类)
|---MyMediaReader(被装饰类)
|---MyDataReader(被装饰类)
|---MyBufferReader(装饰类)

可知:

装饰模式比继承要灵活,避免了继承体系臃肿。而且降低了类与类之间的关系。

装饰类因为增强已有对象,具备的功能和已有的是相同的,只不过提供了更强功能。所以装饰类和被装饰类通常都是属于一个体系中的。

练习:将c盘一个文本文件复制到d盘中。

分析:

复制原理:其实就是将c盘下的文件数据存储到d盘的一个文件中。

步骤:

  1. 在d盘创建一个文件,用于存储c盘文件中的数据。
  2. 定义读取流和c盘文件关联。
  3. 通过不断的读写完成数据存储。
  4. 关闭资源。

代码:

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; public class CoptTest { public static void main(String[] args) throws IOException {
//copy_1();
copy_2();
} public static void copy_2() {
FileWriter fw = null;
FileReader fr = null;
try {
fw = new FileWriter("FileWriterDemo2_copy.java");
fr = new FileReader("FileWriterDemo2.java"); char[] buf = new char[1024];
int len = 0;
if((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) {
e.printStackTrace();
}
if(fw != null)
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*
* 从c盘读一个字符,就往d盘写一个字符
*/
public static void copy_1() throws IOException {
//创建目的地
FileWriter fw = new FileWriter("FileWriterDemo2_copy.txt"); //与已有文件关联
FileReader fr = new FileReader("FileWriterDemo2.java"); //
int ch = 0; while((ch = fr.read()) != -1) {
fw.write(ch);
} fw.close(); fr.close();
} }

用缓冲区技术优化代码:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; public class CopyTextByBuf { public static void main(String[] args) {
BufferedReader bufr = null;
BufferedWriter bufw = null; try {
bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt")); String line = null; while((line = bufr.readLine()) != null) {
bufw.write(line);
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("写入关闭失败");
}
}
} }

图示:

Java IO(一)的更多相关文章

  1. java.IO输入输出流:过滤流:buffer流和data流

    java.io使用了适配器模式装饰模式等设计模式来解决字符流的套接和输入输出问题. 字节流只能一次处理一个字节,为了更方便的操作数据,便加入了套接流. 问题引入:缓冲流为什么比普通的文件字节流效率高? ...

  2. Java:IO流与文件基础

    Java:IO流与文件基础 说明: 本章内容将会持续更新,大家可以关注一下并给我提供建议,谢谢啦. 走进流 什么是流 流:从源到目的地的字节的有序序列. 在Java中,可以从其中读取一个字节序列的对象 ...

  3. Java IO之字符流和文件

    前面的博文介绍了字节流,那字符流又是什么流?从字面意思上看,字节流是面向字节的流,字符流是针对unicode编码的字符流,字符的单位一般比字节大,字节可以处理任何数据类型,通常在处理文本文件内容时,字 ...

  4. java Io流向指定文件输入内容

    package com.hp.io; import java.io.*; public class BufferedWriterTest{ public static void main(String ...

  5. java Io文件输入输出流 复制文件

    package com.hp.io; import java.io.FileInputStream; import java.io.FileNotFoundException; import java ...

  6. java Io流更新文件内容

    package com.hp.io; import java.io.FileOutputStream; import java.io.IOException; public class FileOut ...

  7. java IO流详解

    流的概念和作用 学习Java IO,不得不提到的就是JavaIO流. 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  8. java.io.NotSerializableException: test.io.file.Student

    java.io.NotSerializableException: test.io.file.Student    at java.io.ObjectOutputStream.writeObject0 ...

  9. java.io.IOException: mark/reset not supported

    java.io.IOException: mark/reset not supported at java.io.InputStream.reset(InputStream.java:348) at ...

  10. Java IO流学习总结

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

随机推荐

  1. ios开发--KVO浅析

    目标:监听NSMutableArray对象中增加了什么 代码如下: - (void)viewDidLoad { [super viewDidLoad]; self.dataArray = [NSMut ...

  2. asp.net解决高并发的方案.

    asp.net解决高并发的方案. Posted on 2012-11-27 22:31 75077027 阅读(3964) 评论(1) 编辑 收藏 最近几天一直在读代震军的博客,他是 Discuz!N ...

  3. ubuntu下xampp的安装

    转载:http://blog.csdn.net/zhoushengchao/article/details/6006584 首先,请从www.xampp.org下载最新版XAMPP.然后,将安装文件服 ...

  4. 关于 Google Chrome 中的全屏模式和 APP 模式

    前言:我一直在纠结这篇文章是否应该归类在「前段开发」的范围内,哈哈! 前段时间做了一个项目,涉及到一个要全屏模式去访问网页的需求,因为 Google Chrome 的效率不错,而且专门为 Chrome ...

  5. ListView单击单元格 产生其他控件

    以combobox为例. 假如一行里面只有一个combobox. //在类中声明一个控件数组 private ComboBox[] cmds = null; //initview中调用dao组件获得显 ...

  6. 使用个推的时候出现Installation error: INSTALL_FAILED_DUPLICATE_PERMISSION

    使用个推的时候出现 Installation error: INSTALL_FAILED_DUPLICATE_PERMISSION perm=getui.permissio... 解决办法: 先将手机 ...

  7. android开发 替换bitmap中的颜色值

    /** * 将bitmap中的某种颜色值替换成新的颜色 * @param bitmap * @param oldColor * @param newColor * @return */ public ...

  8. Netsharp FAQ

    1.启动服务器时候不能监听端口,出现如下错误: 回答: 这种问题应该是在win7环境下才有,是没有权限,要以管理员身份运行Netsharp.Elephant.Q.exe. 2.启动服务器的时候,服务端 ...

  9. ASP.NET本质论阅读----线程与异步

    线程 概要:操作系统通过线程对程序的执行进行管理 线程的数据结构:1.线程的核心对象(包含线程的当前寄存器状态),调用线程时-寄存器状态被加载到CPU中. 2.线程环境块TEB:一块用户模式下的内存 ...

  10. Google Guava学习笔记——基础工具类Preconditions类的使用

    Preconditions类是一组静态方法用来验证我们代码的状态.Preconditons类很重要,它能保证我们的代码按照我们期望的执行,如果不是我们期望的,我们会立即得到反馈是哪里出来问题,现在我们 ...