JAVA I/O(一)基本字节和字符IO流
最近再看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流的更多相关文章
- JAVA笔记12__字节、字符缓冲流/打印流/对象流/
/** * !!:以后写流的时候一定要加入缓冲!! * 对文件或其它目标频繁的读写操作,效率低,性能差. * 缓冲流:好处是能更高效地读写信息,原理是将数据先缓冲起来,然后一起写入或读取出来. * * ...
- java中关于编码的问题(字符转换流及字符缓冲流 )
上次我们使用的是字节流,还有一种方式就是字符流,上次说过如何分辨使用哪种流,如果记事本可以读懂则使用字符流,否则使用字节流.使用字符流就需要牵扯到编码的问题,下面给出一种转化流的格式. OutputS ...
- File类的特点?如何创建File类对象?Java中如何操作文件内容,什么是Io流Io流如何读取和写入文件?字节缓冲流使用原则?
重难点提示 学习目标 1.能够了解File类的特点(存在的意义,构造方法,常见方法) 2.能够了解什么是IO流以及分类(IO流的概述以及分类) 3.能够掌握字节输出流的使用(继承体系结构介绍以及常见的 ...
- Java第三阶段学习(二、IO流--------递归,字节流Stream)
一.递归 定义:指方法在方法内调用自己 适用于方法的运算主体不变,但运行的时候,参与运算的方法参数会变化注意:一定要给递归一个出口,否则内存溢出 练习题1:使用递归打印文件夹中所有的文件,包含子目录中 ...
- Java自学第10期——File类与IO流(输入输出流、处理流、转换流、缓冲流、Properties集合、打印流)
1.IO简介 IO(输入输出)通过java.io包下的类和接口来支持,包下包括输入.输出两种IO流,每种输入输出流又可分为字符流和字节流两大类. 2.File类 File类是io包下与平台无关的文件和 ...
- Java高级程序设计笔记 • 【第1章 IO流】
全部章节 >>>> 本章目录 1.1 File类访问文件 1.1.1 File 类 1.1.2 File 类方法 1.1.3 实践练习 1.2 文件过滤器 1.2.1 Fi ...
- java用字符io流复制文件
一.小文件一次快速读写 import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundExceptio ...
- Java第三阶段学习(一、IO流------File类)
一.IO概述: 把内存中的数据存入到硬盘(持久化设备)中叫做:输出(写)Output操作.JAVA软件往电脑硬盘上走叫输出. 把硬盘中的数据读取到到内存里叫做:输入(读)Input操作.电脑硬盘上往J ...
- 字符IO流
输入 FileReader的用法: 1. 找到目标文件 2. 建立数据的输入通道 3. 读取数据 4. 关闭资源 具体实例:从硬盘中读取文件 输出 FileWriter的使用步骤: 1. 找到目标文件 ...
随机推荐
- train_test_split, 关于随机抽样和分层抽样
https://zhuanlan.zhihu.com/p/49991313 在将样本数据分成训练集和测试集的时候,应当谨慎地考虑一下是采用纯随机抽样,还是分层抽样. 通常,数据集如果足够大,纯随机抽样 ...
- SQL SERVER 聚集索引 非聚集索引 区别
转自http://blog.csdn.net/single_wolf_wolf/article/details/52915862 一.理解索引的结构 索引在数据库中的作用类似于目录在书籍中的作用,用来 ...
- [py]python中的特殊类class type和类的两面性图解
生活中的模具 生活中 编程 万物都从无到有, 起于烟尘 () 生产原料,铁 object 车床-生产各类模具 元类即metaclass,对应python的class type 模具-生产各类实在的物品 ...
- 用lua扩展你的Nginx(整理)
首先得声明.这不是我的原创,是在网上搜索到的一篇文章,原著是谁也搞不清楚了.按风格应该是属于章亦春的文章. 整理花了不少时间,所以就暂写成原创吧. 一. 概述 Nginx是一个高性能.支持高并发的,轻 ...
- vcenter web client chrome浏览器打开中文显示乱码
使用如下链接试试看https://x.x.x.x/vsphere-client/?locale=zh_CN&csp
- Approximate Inference 近似推断
引入 统计推断的核心任务,是观察到一些X(可见变量戒可观察变量)之后计算隐变量Z的后验分布p(Z|X),以及在这个后验分布下计算我们所需要的函数的期望.比如,讲EM时,我们曾计算过对数似然函数在隐变量 ...
- 用Anaconda安装TensorFlow+keras
检测目前安装了哪些环境变量:conda info --envs 查看当前有哪些可以使用的tensorflow版本:conda search --full -name tensorflow 查看ten ...
- python ddt 实现数据驱动一
ddt 是第三方模块,需安装, pip install ddt DDT包含类的装饰器ddt和两个方法装饰器data(直接输入测试数据) 通常情况下,data中的数据按照一个参数传递给测试用例,如果da ...
- windows下docker的安装并使用
硬件虚拟化:硬件虚拟化是一种对计算机或操作系统的虚拟.虚拟化对用户隐藏了真实的计算机硬件,表现出另一个抽象计算平台. 打开任务管理器的性能查看是否支持虚拟化技术 下载windows docker ht ...
- Atcoder Tenka1 Programmer Contest 2019 D Three Colors
题意: 有\(n\)个石头,每个石头有权值,可以给它们染'R', 'G', 'B'三种颜色,如下定义一种染色方案为合法方案: 所有石头都染上了一种颜色 令\(R, G, B\)为染了'R', 染了'G ...