字节流的两个基类:

  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. 6.Knockout.Js(加载或保存JSON数据)

    前言 Knockout可以实现很复杂的客户端交互,但是几乎所有的web应用程序都要和服务器端交换数据(至少为了本地存储需要序列化数据),交换数据最方便的就是使用JSON格式 – 大多数的Ajax应用程 ...

  2. web relase

    http://wenku.baidu.com/link?url=uOAV9QwXGGLjeqt6M1KTqwp0Jbhhguvz9IxExCHNiUlrYMX584Io3ByNJJIkAVzEqzv9 ...

  3. TFS(Taobao File System)安装方法

    文章目录: 一.TFS(Taobao File System)安装方法 二.TFS(Taobao File System)配置dataServer.分区.挂载数据盘 三.TFS(Taobao File ...

  4. mssql 动态添加数据库用户

    USE [master]GOCREATE LOGIN [admin] WITH PASSWORD=N'123456', DEFAULT_DATABASE=[test], CHECK_EXPIRATIO ...

  5. SQL SERVER定时任务执行跟踪--供远程查看 [原创]

    一.背景 每次查需要优化的SQL都需要上外网,通过Profiler,报表或者DMV执行特定sql来查找,来回跑很麻烦,能不能在本地直接监控外网的好性能的SQL呢?方法是有的,我们可以通过把Profil ...

  6. jQuery Dialog弹出层对话框插件

    Dialog.js的相关注释已经添加,可以按照注释,进行相关样式的修改,适用于自定义的各个系统! dialog.js /** * jQuery的Dialog插件. * * @param object ...

  7. 圆形DIV

    <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" ...

  8. 使用NPOI和线程池快速加载EXCEL数据

    private void FilterData() { List<Task> tasks = new List<Task>(); IWorkbook workbook = Cs ...

  9. 【转载】c/c++在windows下获取时间和计算时间差的几种方法总结

    一.标准C和C++都可用 1.获取时间用time_t time( time_t * timer ),计算时间差使用double difftime( time_t timer1, time_t time ...

  10. Lessons learned from manually classifying CIFAR-10

    Lessons learned from manually classifying CIFAR-10 Apr 27, 2011 CIFAR-10 Note, this post is from 201 ...