数据发生流动,都会涉及到IO问题。在当今这个数据大爆炸时代,I/O 问题尤其突出,很容易成为一个性能瓶颈。
JAVA中的I/O主要涉及到两个方向:磁盘I/O工作机制,网络I/O工作机制。
I/O基本框架
Java 的 I/O 操作类在包 java.io 下,大概有将近 80 个类,但是这些类大概可以分成四组,分别是:
- 基于字节操作的 I/O 接口:InputStream 和 OutputStream
- 基于字符操作的 I/O 接口:Writer 和 Reader
- 基于磁盘操作的 I/O 接口:File
- 基于网络操作的 I/O 接口:Socket
前两组主要是根据传输数据的数据格式,后两组主要是根据传输数据的方式,虽然 Socket 类并不在 java.io 包下,但是我仍然把它们划分在一起,因为我个人认为 I/O 的核心问题要么是数据格式影响 I/O 操作,要么是传输方式影响 I/O 操作,也就是将什么样的数据写到什么地方的问题,I/O 只是人与机器或者机器与机器交互的手段,除了在它们能够完成这个交互功能外,我们关注的就是如何提高它的运行效率了,而数据格式和传输方式是影响效率最关键的因素了。我们后面的分析也是基于这两个因素来展开的。
基于字节的 I/O 操作接口
基于字节的 I/O 操作接口输入和输出分别是:InputStream 和 OutputStream,InputStream 输入流的类继承层次如下图所示:
输入流根据数据类型和操作方式又被划分成若干个子类,每个子类分别处理不同操作类型,OutputStream 输出流的类层次结构也是类似,如下图所示:
图 2. OutputStream 相关类层次结构
java io的开始:文件
1. 我们主要讲的是流,流的本质也是对文件的处理,我们循序渐进一步一步从文件将到流去。
2. java 处理文件的类 File,java提供了十分详细的文件处理方法。
另外一个BLOG对文件File类有了进一步说明。
输入流:从磁盘或网络取得提供给程序(存放在内存)使用的数据。
输出流:数据已经在程序中存在(内存),现要写入到磁盘或者网络。
我理解的“流”是一个中介对象。通过它,磁盘和内存(buffer)实现交互。
字节输出流:OutputStream (抽象类)
方法:
close() 关闭输出流
flush() 刷新缓冲区
write() ;向输出流中写入byte[]
write(int b) 向输出流中写入一个字节
FileOutputStream ;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; /** * Created by li on 2016/10/24. * 1 */ public class FileInputDemo { public static void main(String[] args) throws IOException { File file = new File("D:/asd.txt"); if (!file.exists()) { System.out.println(file.createNewFile()); } OutputStream outputStream = new FileOutputStream(file, true); outputStream.write("Hello Word".getBytes("utf-8"));
outputStream.close(); //outputStream.write("Hello Word".getBytes("utf-8"));
} }
注意任何流对象都应该关闭,关闭后再往里面做读写错字可是不能了。
OutputStream outputStream = new FileOutputStream(file, true);
设置为true可在文件后追加,否则清空文件。
InputStream
只有一个构造方法,仅仅用于创建对象。
方法
Methods
Modifier and Type | Method and Description |
---|---|
int |
返回输入流指向的数据能被读取或者跳过的字节大小。
|
void | close() 关闭输入流,关闭之后输入流指向数据为空,再做操作会报错。 |
void | mark(int readlimit) 标记属于流位置。 |
boolean | markSupported() 测试输入流是否支持标记和重置方法。 |
abstract int | read() 从输入流指向的数据仓库中读取数据到内存。 |
int | read(byte[] b) 读取输入流指向的数据到内存b字节中。 |
int | read(byte[] b, int off, int len) 读取指定长度字节 |
void | reset() 重置标记。 |
long | skip(long n) 跳读输入流指向数据。 |
import java.io.*; /** * Created by li on 2016/10/24. * 1 */ public class FileInputDemo { public static void main(String[] args) throws IOException { File file = new File("D:/asd.txt"); if (!file.exists()) { System.out.println(file.createNewFile()); } OutputStream outputStream = new FileOutputStream(file); outputStream.write("输出输出".getBytes()); InputStream inputStream = new FileInputStream(file); // System.out.println(inputStream.available()); byte[] bytes = new byte[1024]; int len = inputStream.read(bytes); String s = new String(bytes, 0, len); System.out.println(s); inputStream.close(); } }
字符流不做介绍,注意 OutputStreamWriter 和InputStreamReader 可在字节流和字符流中变换。
内存操作流
ByteoutputStream 用于将内存中的数据输出。 这个类的构造器好像是唯一不需要添加参数的IO类,其他类可以用它指定为构造器输入,做为中介将数据传输给它,然后该对象有一个方法toByteArray()用于把输入的东西转为字节数组。(搭配ObjectOutputStream使用)
ByteIntputStream 用于读取数据到内存。
内存操作流一般用于生成一些临时信息,假如不用内存操作流,临时信息需要存放在文件中,比较麻烦。
如将对象转为二进制需要用到。
import com.sun.org.apache.xpath.internal.SourceTree; import java.io.Serializable; public class Preson implements Serializable { String name; void tell() { System.out.println("name is " + name); } }
import java.io.*; import java.time.Period; public class Obj { public static void main(String[] args) throws IOException, ClassNotFoundException { Preson preson = new Preson(); preson.name = "lisi"; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(preson); byte[] bytes = byteArrayOutputStream.toByteArray(); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); Preson object = (Preson) objectInputStream.readObject(); object.tell(); System.out.println(object.name); } }
管道流:用于两个线程之间通信。 要进行输出,必须把输出流连在输入流上。
代码实例:
import java.io.IOException; import java.io.PipedOutputStream; public class pip extends Thread { private PipedOutputStream pipedOutputStream = null; public void send() { this.pipedOutputStream = new PipedOutputStream(); } public PipedOutputStream getPipedOutputStream() { return pipedOutputStream; } @Override public void run() { String s = "Hello Word"; try { this.pipedOutputStream.write(s.getBytes("utf-8")); this.pipedOutputStream.close(); ; } catch (IOException e) { e.printStackTrace(); } } }
import java.io.IOException; import java.io.PipedInputStream; public class Get extends Thread { private PipedInputStream pipedInputStream = null; public void get() { this.pipedInputStream = new PipedInputStream(); } public PipedInputStream getPipedInputStream() { return pipedInputStream; } @Override public void run() { byte[] bytes = new byte[1024]; int len = 0; try { len = this.pipedInputStream.read(bytes); this.pipedInputStream.close(); System.out.println(new String(bytes)); } catch (IOException e) { e.printStackTrace(); } } }
import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; public class Demo { public static void main(String[] args) throws IOException { pip pip1 = new pip(); pip1.send(); Get get = new Get(); get.get(); PipedInputStream pipedInputStream = get.getPipedInputStream(); PipedOutputStream pipedOutputStream = pip1.getPipedOutputStream(); pipedOutputStream.connect(pipedInputStream); pip1.start(); get.start(); } }
现对此不做细纠。以后写到多线程再说吧。
再列举一些类
数据操作流:DataOutputStream 主要针对数据进行操作
合并流:SequenceInputStream 将两个文件合并为一个文件。
压缩流: ZipInpputStream 可将文件或文件夹压缩为ZIP,JAR,GZIP形式。