最近再看I/O这一块,故作为总结记录于此。JDK1.4引入NIO后,原来的I/O方法都基于NIO进行了优化,提高了性能。I/O操作类都在java.io下,大概将近80个,大致可以分为4类:

  • 基于字节操作的I/O接口:以InputStream和OutputStream为基类,也是I/O操作的基础。
  • 基于字符操作的I/O接口:以Reader和Writer为基类,字符的读写是基于字节进行的,中间进行了转换。
  • 基于磁盘操作的I/O接口:主要是File,代表目录下的所有文件。
  • 基于网络操作的I/O接口:主要是Socket,实现网络数据的传输。

本文大致总结一下基于字节和字符的I/O操作,主要理清JAVA I/O中的类关系。

摘自《Java编程思想》:类库中常使用“流”这个抽象的概念,代表任何有能力产出数据的数据源对象或有能力接收数据的接收端对象。其屏蔽了I/O设备中数据处理的细节。I/O类分为输入和输出两类。通过 继承,任何InputStream或Reader的派生类都含有read()方法,用于读取单个字节或字符,任何OutputStream或Writer的派生类都含有write()方法,用于写单个字节或字符。通常不会使用单一的类创建流对象,而是通过叠合多个对象提供期望的功能(即采用装饰器模式)。

一、基于字节的I/O操作

1. InputStream类型

InputStream的作用表示那些从不同数据源产生输入的类,即其派生类多是不同数据源对应的流对象。如下:

  ByteArrayInputStream:从内存缓冲区读取字节数组

  FileInputStream:从文件中读取字节,其构造参数可以是文件名、File对象或FileDescriptor

  ObjectInputStream:主要用于反序列化,读取基本数据类型或对象

  PipedInputStream:产生用于写入相关PipedOutputStream的数据,实现“管道化”概念,多用于多线程中。

  FilterInputStream:作为装饰器类,其子类与上述不同流对象叠合使用,以控制特定输入流。

其中,FilterInputStream的子类通过添加属性或有用的接口控制字节输入流,其构造函数为InputStream,常见的几个如下:

  DataInputStream:与DataOutputStream搭配使用,读取基本类型数据及String对象。

  BufferdInputStream:使用缓冲区的概念,避免每次都进行实际读操作,提升I/O性能。(不是减少磁盘IO操作次数(这个OS已经帮我们做了),而是通过减少系统调用次数来提高性能的

  InflaterInputStream:其子类GZIPInputStream和ZipInputStream可以读取GZIP和ZIP格式的数据。

2. OutputStream类型

与InputStream相对应,OutputStream的作用表示将数据写入不同的数据源,常用的输出流对象如下:

  ByteArrayOutputStream:在内存中创建缓冲区,写入字节数组

  FileOutputStream:将字节数据写入文件中,其构造参数可以是文件名、File对象或FileDescriptor

  ObjectOutputStream:主要用于序列化,作用于基本数据类型或对象

  PipedOutputStream:任何写入其中的数据,都会自动作为相关PipedInputStream的输出,实现“管道化”概念,多用于多线程中。

  FilterOutputStream:作为装饰器类,其子类与上述不同流对象叠合使用,以控制特定输出流。

其中,FilterOutputStream的子类通过添加属性或有用的接口控制字节输入流,其构造函数为InputStream,常见的几个如下:

  DataOutputStream:与DataInputStream搭配使用,写入基本类型数据及String对象。

  PrintStream:用于格式化输出显示。

  BufferdOutputStream:使用缓冲区的概念,避免每次都进行实际写操作,提升I/O性能。

  DeflaterOutputStream:其子类GZIPOutputStream和ZipOutputStream可以写GZIP和ZIP格式的数据。

二、基于字符的I/O操作

不管是磁盘还是网络传输,数据处理的最小单元都是字节,而不是字符。故所有I/O操作的都是字节而不是字符。为了方便引入了字符操作,其中涉及字节到字符的转换适配,InputStreamReader可以把InputStream转为Reader,OutputStreamWriter可以把OutputStream转为Writer。对上述按字节操作的流对象,可以采用FilterInputStream和FilterOutputStream的装饰器子类控制流。Reader和Writer沿用相似的思想,但不完全相同。

1. Reader类型

继承自Reader类的,字符型数据来源常用类,如下:

  InputStreamReader:字节与字符适配器,子类包含FileReader(以字符形式读取文件) 

  CharArrayReader:读取字符数组

  StringReader:数据源是字符串

  BufferedReader:读取字符输入流,并进行缓存,常用法:BufferedReader in = new BufferedReader(new FileReader("foo.in")); 表示采用缓存的方式从文件读取数据

  PipedReader:管道形式读取字符  

  FilterReader:对Reader装饰,直接使用的不多,如PushbackReader

2. Writer类型

继承自Writer类的,字符型数据来源常用类,如下:

  OutputStreamReader:字节与字符适配器,子类包含FileWriter(以字符形式写文件) 

  CharArrayWriter:写字符数组

  StringWriter:内部有StringBuffer,用于缓存构造字符串

  BufferedWriter:字符输出流,常用法:PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out"))); 表示将数据格式化并用缓存的方式写入文件

  PipedWriter:管道形式输出字符  

  FilterWriter:对Writer装饰,如XMLWriter

三、自我独立的类RandomAccessFile

该类可以随机访问文件,实现了DataOutput, DataInput,不是InputStream或OutputStream继承层次结构的一部分。与其他I/O类本质有所不同,可以在一个文件内向前或向后移动。

工作方式类似与DataOutputStream和 DataInputStream,用法如下:

  RandomAccessFile randomAccessFile = new RandomAccessFile("data.dat", "rw")

其中,r代表读,w代表写。

四、常用实例

1. 缓存输入文件

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/**
* 缓存输入文件,防止频繁与文件交互
* 1.采用装饰器模式,BufferedReader从FileReader中读取字符,FileReader为字符数据源
* 2.FileReader继承InputStreamReader,实例化一个FileInputStream对象作为字节数据源,
* 3.InputStreamReader继承Reader,包含StreamDecoder,将字节数据转换为字符;编码格式没有指定时采用默认编码。
* 4.Reader可以实现对FileInputStream加锁*/
public class BufferedInputFile { public static String read(String filename) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader(filename));
String s;
StringBuilder sb = new StringBuilder();
while((s = bufferedReader.readLine()) != null) {
sb.append(s + "\n");
}
bufferedReader.close();
return sb.toString();
} public static void main(String[] args) throws IOException {
System.out.println(read("src/com/test/io/BufferedInputFile.java"));
}
}
//输出类文件到控制台

2.从内存输入

import java.io.IOException;
import java.io.StringReader;
/**
* 将文件读入内存
* 具体形式:new StringReader(new BufferdReader(new FileReader(filename)))
* 通过缓存读文件,防止每读一个字节,都与文件直接交互*/
public class MemoryINput { static String filename = "src/com/test/io/BufferedInputFile.java"; public static void main(String[] args) throws IOException{
StringReader in = new StringReader(BufferedInputFile.read(filename));
int c;
while((c = in.read()) != -1) {
System.out.println((char)c);
}
}
}

3.格式化内存输入

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
/**
* 格式化的内存输入
* 1.in.readByte()读取字节,无法判断字节是否有效合法,因此无法判断结尾,报java.io.EOFException
* 2.采用available()方法预估还有多少字节可存取*/
public class FormattedMemoryInput { public static void main(String[] args) throws IOException {
DataInputStream in = new DataInputStream(
new ByteArrayInputStream(BufferedInputFile.read("src/com/test/io/BufferedInputFile.java").getBytes()));
// byte c;
// while((c = in.readByte()) !=-1) {
// System.out.print((char) c);
// }
while(in.available() != 0) {
System.out.print((char) in.readByte());
}
}
}

4.基本文件输出

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringReader;
/**
* 基本文件输出
* 1.先利用BufferedInputFile和StringReader将数据读到内存,记住输入流已经关闭
* 2.new PrintWriter(new BufferedWriter(new FileWriter(outfile)))输出字符到文件
* 注意,此处使用BufferedWriter进行缓冲,防止每个字节都与文件交互
* 3.文本文件输出快捷方式 PrintWriter out = new PrintWriter(outfile);
* 底层实现了缓存new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName)))*/
public class BasicFIleOutput { static String filename = "src/com/test/io/BufferedInputFile.java";
static String outfile = "BasicFIleOutput.out"; public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new StringReader(BufferedInputFile.read(filename)));
// PrintWriter out = new PrintWriter(new FileWriter(outfile));
// PrintWriter out = new PrintWriter(outfile);
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outfile)));
int lineCount = 1;
String s;
while((s = in.readLine()) != null) {
out.println(lineCount++ + ":" +s);
}
out.close();
}
}

5.存储与恢复数据

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 1.DataInputStream能从DataOutputStream中准确读取数据
* 2.读数据时,必须知道数据精确的位置,否则会报错
* 3.writeUTF与readUTF采用UTF-8的变体进行编码
*
*/
public class StoringAndRecoveringData { public static void main(String[] args) throws IOException { DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("Data.txt")));
out.writeDouble(3.12159);
out.writeUTF("this is pi");
out.writeDouble(1.4414);
out.writeUTF("this is root of 2");
out.close(); DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("Data.txt")));
System.out.println(in.readDouble());
System.out.println(in.readUTF());
System.out.println(in.readDouble());
in.close();
}

五、总结

1.  I/O操作本质是基于字节流的操作,InputStream和OutputStream对输入和输出源进行了抽象,其子类代表不同的数据源。

2. FilterInputStream和FilterOutputStream采用装饰器模式,对输入和输出流进行控制,如采用缓冲器、读基本数据类型等。

3. Reader和Writer代表基于字符的操作,底层是基于字节操作,经过InputStreamReader和OutputStreamWriter,采用StreamEncoder和StreamDecoder,将输入输出流,按Charset进行转换

4. 所有基于字节或字符的操作,基本都采用叠合的方式。如输入流采用缓存的方式从文件中读取,输出流采用缓存的方式按格式输出到文件。

5. 理清他们之间的关系,有利于了解I/O的操作过程。

JAVA I/O(一)基本字节和字符IO流的更多相关文章

  1. JAVA笔记12__字节、字符缓冲流/打印流/对象流/

    /** * !!:以后写流的时候一定要加入缓冲!! * 对文件或其它目标频繁的读写操作,效率低,性能差. * 缓冲流:好处是能更高效地读写信息,原理是将数据先缓冲起来,然后一起写入或读取出来. * * ...

  2. java中关于编码的问题(字符转换流及字符缓冲流 )

    上次我们使用的是字节流,还有一种方式就是字符流,上次说过如何分辨使用哪种流,如果记事本可以读懂则使用字符流,否则使用字节流.使用字符流就需要牵扯到编码的问题,下面给出一种转化流的格式. OutputS ...

  3. File类的特点?如何创建File类对象?Java中如何操作文件内容,什么是Io流Io流如何读取和写入文件?字节缓冲流使用原则?

    重难点提示 学习目标 1.能够了解File类的特点(存在的意义,构造方法,常见方法) 2.能够了解什么是IO流以及分类(IO流的概述以及分类) 3.能够掌握字节输出流的使用(继承体系结构介绍以及常见的 ...

  4. Java第三阶段学习(二、IO流--------递归,字节流Stream)

    一.递归 定义:指方法在方法内调用自己 适用于方法的运算主体不变,但运行的时候,参与运算的方法参数会变化注意:一定要给递归一个出口,否则内存溢出 练习题1:使用递归打印文件夹中所有的文件,包含子目录中 ...

  5. Java自学第10期——File类与IO流(输入输出流、处理流、转换流、缓冲流、Properties集合、打印流)

    1.IO简介 IO(输入输出)通过java.io包下的类和接口来支持,包下包括输入.输出两种IO流,每种输入输出流又可分为字符流和字节流两大类. 2.File类 File类是io包下与平台无关的文件和 ...

  6. Java高级程序设计笔记 • 【第1章 IO流】

    全部章节   >>>> 本章目录 1.1 File类访问文件 1.1.1 File 类 1.1.2 File 类方法 1.1.3 实践练习 1.2 文件过滤器 1.2.1 Fi ...

  7. java用字符io流复制文件

    一.小文件一次快速读写 import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExceptio ...

  8. Java第三阶段学习(一、IO流------File类)

    一.IO概述: 把内存中的数据存入到硬盘(持久化设备)中叫做:输出(写)Output操作.JAVA软件往电脑硬盘上走叫输出. 把硬盘中的数据读取到到内存里叫做:输入(读)Input操作.电脑硬盘上往J ...

  9. 字符IO流

    输入 FileReader的用法: 1. 找到目标文件 2. 建立数据的输入通道 3. 读取数据 4. 关闭资源 具体实例:从硬盘中读取文件 输出 FileWriter的使用步骤: 1. 找到目标文件 ...

随机推荐

  1. Python哈希表的例子:dict、set

    dict(字典) Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 和list比较,dic ...

  2. spring boot继承web和mybatis时,调用接口删除记录出现的空指针以及解决办法

    前两天在学spring boot的时候,出现了一个很奇怪的错误,因为是第一次使用spring boot,所以没想到会遇到这种莫名其妙的bug,即调用接口删除数据库中一条记录的时候,数据库中记录事实上以 ...

  3. Python开发【数据结构】:字典内部剖析

    字典内部剖析 开篇先提出几个疑问: 所有的类型都可以做字典的键值吗? 字典的存储结构是如何实现的? 散列冲突时如何解决? 最近看了一些关于字典的文章,决定通过自己的理解把他们写下来:本章将详细阐述上面 ...

  4. JAVA中只有值传递

    今天,我在一本面试书上看到了关于java的一个参数传递的问题: 写道 java中对象作为参数传递给一个方法,到底是值传递,还是引用传递? 我毫无疑问的回答:“引用传递!”,并且还觉得自己对java的这 ...

  5. linux 安装mysql yum方式

    centos 6 #二进制rpm包安装 yum -y install mysql-server mysql centos7 mariadb和mysql一样的 只是一个分支 防止 mysql 被Orac ...

  6. CMSPRESS-PHP无限级分类

    原博文地址:http://blog.sina.com.cn/s/blog_75ad10100101mrv0.html 当你学习php无限极分类的时候,大家都觉得一个字“难”我也觉得很难,所以,现在都还 ...

  7. 杀死正在运行的进程: linux

    1:杀死正在运行的进程:使用ps -aux|grep labor   查出进程PID 2:使用kill  PID  将进程杀死.

  8. 使用gradle构建多模块springboot项目,打jar包

    官方文档: https://spring.io/guides/gs/rest-service/  参考:http://blog.csdn.net/u013360850/article/details/ ...

  9. [js]ext.js探索

    Ext JS 经常会遇到布局等头疼的问题,一直在用bootstrap,但是我不喜欢这玩意出的效果想找个合适的js架构入手 http://examples.sencha.com/extjs/6.6.0/ ...

  10. python selenium webdriver处理浏览器滚动条

    用键盘右下角的UP,DOWN按键来处理页面滚动条 这种方法很灵活用起来很方便!!!! from selenium import webdriver import time from selenium. ...