字节流的两个基类:

  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. android开发系列之socket编程

    上周在项目遇到一个接口需求就是通讯系列必须是socket,所以在这篇博客里面我想谈谈自己在socket编程的时候遇到的一些问题. 其实在android里面实现一个socket通讯是非常简单的,我们只需 ...

  2. python的内存管理

    1.在Python中,整数和短小的字符,Python都会缓存这些对象,以便重复使用.当我们创建多个等于1的引用时,实际上是让所有这些引用指向同一个对象. a = 1 b = 1 print hex(i ...

  3. php xml转为xml或者json

    <?php class XmlToArray { private $xml; private $contentAsName="content" ; private $attr ...

  4. shell 基本结构

    就像其他的编程语言一样,shell也有三种基本的结构:顺序结构.分支结构.循环结构.顺序结构就是按照命令的出现顺序依次执行,比较简单.如下分别介绍分支结构和循环结构. 分支结构 格式1: if com ...

  5. homework-03 扑街。。

    1.思路 我的思路是利用进程间通信间来实现题目要求. 第一次打开的程序与第二次打开的程序并不是同一个进程,故需要进程间通信来是传递信息. windows下进程间通信的方式有很多,如文件映射.共享内存. ...

  6. WPF——数据绑定(二)绑定方法—绑定本地对象

    注意:本人初学WPF,文中表达或技术性问题请勿见怪,欢迎指正,谢谢 标记拓展语法:绑定到本地对象 什么是绑定到本地对象,我个人理解就是实现UI层上两个或多个控件的相互关联,一个控件的状态改变,导致另一 ...

  7. Android -- 分享功能和打开指定程序

    打开指定程序                                                                                Intent intent ...

  8. 【每日scrum】NO.4

    1.掌握了如何求两点间的最短距离这个算法.

  9. Netsharp快速入门(之1) 介绍及需求说明

    作者:秋时 杨昶   时间:2014-02-15  转载须说明出处 第一章 快速入门介绍 Netsharp是一个企业基础业务管理平台,介绍Netsharp分三个系列,分别是: 1.         N ...

  10. 深入探讨Java类加载机制

    一.前言 毕业至今,已经三年光景,平时基本接触不到关于类加载器的技术(工作上),相信很多同行在开始工作后很长一段时间,对于类的加载机制都没有深入的了解过,之前偶然的机会接触了相关的知识,感觉挺有意思, ...