流是一种抽象概念,它代表了数据的无结构化传递。用来进行输入输出操作的流就称为IO流。

一、IO流结构

1、流的分类方式

按流向分

从文件/网络/内存等(数据源)到程序是输入流;从程序到文件/网络/内存等(数据源)是输出流

按数据处理单位分

以字节为单位传输数据的流,以Stream结尾的是字节流;以字符为单位传输数据的流,以Reader结尾的是输入字符流,以Writer结尾的都是输出字符流。

按功能(层次)分

用于直接操作目标设备的流是节点流;处理流(也叫过滤流)是对一个已存在的流的连接和封装,通过对数据的处理为程序提供更为强大、灵活的读写功能。

2、IO流的结构

如下图所示:

注意:

所有的字节输入流类都是InputStream的子类;所有的字节符输入流类都是Reader的子类;所有的字节节输出流类都是OutputStream的子类;所有的字节符输出流类都是Writer的子类,且他们都为抽象类。

3、IO流四大抽象类

InputStream的基本方法:

 public abstract int read() throws IOException {}//从输入流中读取数据的下一个字节, 返回读到的字节值.若遇到流的末尾,返回-1
public int read(byte[] b) throws IOException {}//从输入流中读取 b.length 个字节的数据并存储到缓冲区数组b中.返回的是实际读到的字节总数
public int read(byte[] b, int off, int len) throws IOException {}//读取 len 个字节的数据,并从数组b的off位置开始写入到这个数组中
public void close() throws IOException {}//关闭此输入流并释放与此流关联的所有系统资源
public int available() throws IOException {}//返回此输入流下一个方法调用可以不受阻塞地从此输入流读取(或跳过)的估计字节数
public long skip(long n) throws IOException {}//跳过和丢弃此输入流中数据的 n 个字节,返回实现路过的字节数。

OutputStream的基本方法:

public abstract void write(int b) throws IOException {}//将指定的字节写入此输出流。
public void write(byte[] b) throws IOException {}// 将 b.length 个字节从指定的 byte 数组写入此输出流。
public void write(byte[] b, int off, int len) throws IOException {}//将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
public void flush() throws IOException {}//刷新此输出流并强制写出所有缓冲的输出字节。
pulbic void close() throws IOException {}//关闭此输出流并释放与此流有关的所有系统资源。

Reader的基本方法:

public int read() throws IOException {}//读取单个字符,返回作为整数读取的字符,如果已到达流的末尾返回-1
public int read(char[] cbuf) throws IOException {}//将字符读入数组,返回读取的字符数
public abstract int read(char[] cbuf, int off, int len) throws IOException {}//读取 len 个字符的数据,并从数组cbuf的off位置开始写入到这个数组中
public abstract void close() throws IOException {}//关闭该流并释放与之关联的所有资源
public long skip(long n) throws IOException {}//跳过n个字符。
public int available() //还可以有多少能读到的字节数

Writer的基本方法:

public void write(int c) throws IOException {} //写入单个字符
public void write(char[] cbuf) throws IOException {} //写入字符数组
public abstract void write(char[] cbuf, int off, int len) throws IOException {} //写入字符数组的某一部分
public void write(String str) throws IOException {} //写入字符串
public void write(String str, int off, int len) throws IOException {}//写字符串的某一部分
public abstract void close() throws IOException {} //关闭此流,但要先刷新它
public abstract void flush() throws IOException {} //刷新该流的缓冲,将缓冲的数据全写到目的地

二、IO流的具体使用

1、FileInputStream 和 FileOutputStream

public static void fileInputStreamTest() {
File f1 = new File("D:\\in.txt");
File f2 = new File("D:\\out.txt");
try {
FileInputStream fi = new FileInputStream(f1);
FileOutputStream fo = new FileOutputStream(f2);
byte[] buf = new byte[521];
int len = 0;
while((len = fi.read(buf)) != -1){
fo.write(buf, 0, len);
}
fo.flush();
fo.close();
fi.close();
} catch (Exception e) {
e.printStackTrace();
}
}

2、PipedOutputStream和PipedintputStream

Java里的管道输入流PipedInputStream与管道输出流PipedOutputStream实现了类似管道的功能,用于不同线程之间的相互通信。

Java的管道输入与输出实际上使用的是一个循环缓冲数组来实现,这个数组默认大小为1024字节。输入流PipedInputStream从这个循环缓冲数组中读数据,输出流PipedOutputStream往这个循环缓冲数组中写入数据。当这个缓冲数组已满的时候,输出流PipedOutputStream所在的线程将阻塞;当这个缓冲数组首次为空的时候,输入流PipedInputStream所在的线程将阻塞。Java在它的jdk文档中提到不要在一个线程中同时使用PipeInpuStream和PipeOutputStream,这会造成死锁。

public class WriteThread implements Runnable{
private PipedOutputStream pout; WriteThread(PipedOutputStream pout){
this.pout= pout;
} @Override
public void run() {
try {
System.out.println("W:开始将数据写入:但等个5秒让我们观察...");
Thread.sleep(5000); //释放cpu执行权5秒
pout.write("writePiped 数据...".getBytes()); //管道输出流
pout.close();
} catch(Exception e) {
throw new RuntimeException("W:WriteThread写入失败...");
}
}
} public class ReadThread implements Runnable{
private PipedInputStream pin; ReadThread(PipedInputStream pin) {
this.pin=pin;
} @Override
public void run() { //由于必须要覆盖run方法,所以这里不能抛,只能try
try {
System.out.println("R:读取前没有数据,阻塞中...等待数据传过来再输出到控制台...");
byte[] buf = new byte[1024];
int len = pin.read(buf); //read阻塞
System.out.println("R:读取数据成功,阻塞解除...");
String s= new String(buf,0,len);
System.out.println(s); //将读取的数据流用字符串以字符串打印出来
pin.close();
} catch(Exception e) {
throw new RuntimeException("R:管道读取流失败!");
}
}
} public class Test {
public static void main(String[] args) throws IOException {
PipedInputStream pin = new PipedInputStream();
PipedOutputStream pout = new PipedOutputStream();
pin.connect(pout); //输入流与输出流连接 ReadThread readTh = new ReadThread(pin);
WriteThread writeTh = new WriteThread(pout);
new Thread(readTh).start();
new Thread(writeTh).start();
}
}

3、BufferedInputStream和BufferedOutputStream

FileInputStream和FileOutputStream 在使用时,我们介绍了可以用byte数组作为数据读入的缓存区,以读文件为列,读取硬盘的速度远远低于读取内存的数据,为了减少对硬盘的读取,通常从文件中一次读取一定长度的数据,把数据存入缓存中,在写入的时候也是一次写入一定长度的数据,这样可以增加文件的读取效率。我们在使用FileInputStream的时候是用byte数组来做了缓存,而BufferedInputStream and BufferedOutputStream已经为我们增加了这个缓存功能。

public static void fileBufferTest() {
File f1 = new File("D:\\in.txt");
File f2 = new File("D:\\out.txt");
try {
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(f1));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(f2));
byte[] data = new byte[1];
while(bufferedInputStream.read(data)!=-1) {
bufferedOutputStream.write(data);
}
//将缓冲区中的数据全部写出
bufferedOutputStream.flush();
bufferedInputStream.close();
bufferedOutputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}

4、读写对象ObjectInputStream和ObjectOutputStream

public class ObjectStream {
public static void main(String[] args) {
ObjectStream.objectStreamTest();
} public static void objectStreamTest() {
Demo newObject;
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:/123.obj")));
oos.writeObject(new Demo());
oos.flush();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:/123.obj")));
newObject = (Demo)ois.readObject();
System.out.println(newObject.num);
ois.close();
oos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
} class Demo implements Serializable{
private static final long serialVersionUID = 1L;
int num = 30;
}

5、SequenceInputStream

合并流,将与之相连接的流集组合成一个输入流并从第一个输入流开始读取, 直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。 合并流的作用是将多个源合并合一个源。可接收枚举类所封闭的多个字节流对象。

public class Test {
public static void main(String[] args) {
doSequence();
} private static void doSequence() {
SequenceInputStream sis = null; // 创建一个合并流的对象
BufferedOutputStream bos = null; // 创建输出流。
try {
// 构建流集合
Vector<InputStream> vector = new Vector<InputStream>();
vector.addElement(new FileInputStream("D:/in.txt"));
vector.addElement(new FileInputStream("D:/out.txt"));
Enumeration<InputStream> e = vector.elements();
sis = new SequenceInputStream(e);
bos = new BufferedOutputStream(new FileOutputStream("/Users/zhengchao/cctv/File_OUT.txt"));
// 读写数据
byte[] buf = new byte[1024];
int len = 0;
while ((len = sis.read(buf)) != -1) {
bos.write(buf, 0, len);
bos.flush();
}
} catch (Exception e1) {
e1.printStackTrace();
} finally {
try {
if (sis != null)
sis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bos != null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

6、FileReader与FileWriter

public static void fileReaderTest() {
File f1 = new File("D:\\in.txt");
File f2 = new File("D:\\out.txt");
try {
FileReader fr = new FileReader(f1);
FileWriter fw = new FileWriter(f2);
char[] ch = new char[512];
int len = 0;
while((len = fr.read(ch)) != -1){
fw.write(ch, 0, ch.length);
}
fw.flush();
fw.close();
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}

7、BufferedReader和BufferedWriter

public static void fileBufferReaderWriteTest() {
File f1 = new File("D:\\in.txt");
File f2 = new File("D:\\out.txt");
try {
BufferedReader br=new BufferedReader(new FileReader(f1));
BufferedWriter bw=new BufferedWriter(new FileWriter(f2)); String s=br.readLine();
while(null!=s) {
bw.write(s);
//由于BufferedReader的readLine()是不读入换行符的,所以写入换行时须用newLine()方法
bw.newLine();
s=br.readLine();
}
br.close();
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}

注:在使用过程中应注意将编码格式设置为UTF-8,否则文件写入会乱码。

以上只是IO流的部分类,用于对IO流相关知识进行查阅,后面再实际的工作中也会根据实际需求不断添加。

参考自:

https://blog.csdn.net/zhengchao1991/article/details/53033137

https://blog.csdn.net/SilenceOO/article/details/50995062

https://blog.csdn.net/Yue_Chen/article/details/72772445

理解Java之IO流的更多相关文章

  1. 第15章-输入/输出 --- 理解Java的IO流

    (一)理解Java的IO流 JAVA的IO流是实现输入/输出的基础,它可以方便地实现数据的输入/输出操作,在Java中把不同的输入/输出(键盘.文件.网络连接等)抽象表述为"流"( ...

  2. java的IO流

    java的IO流继承四大抽象类分别是字节流 inputStream outputStream与字符流 read write.怎么理解记忆很重要. 直接连接读写对象的是结点流,例如对文件读取字节类的名字 ...

  3. Java基础-IO流对象之压缩流(ZipOutputStream)与解压缩流(ZipInputStream)

    Java基础-IO流对象之压缩流(ZipOutputStream)与解压缩流(ZipInputStream) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 之前我已经分享过很多的J ...

  4. Java基础——IO流

    今天刚刚看完java的io流操作,把主要的脉络看了一遍,不能保证以后使用时都能得心应手,但是最起码用到时知道有这么一个功能可以实现,下面对学习进行一下简单的总结: IO流主要用于硬板.内存.键盘等处理 ...

  5. 【Java】IO流简单分辨

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/5827509.html Java的IO流体系十分庞大,并且体系层次稍复杂,很容易记混或记错.在此,我把平时经常用 ...

  6. Java - 文件(IO流)

    Java - 文件 (IO)   流的分类:     > 文件流:FileInputStream | FileOutputStream | FileReader | FileWriter     ...

  7. Java中IO流的总结

    有关Java中IO流总结图 流分类 按方向分 输入流 输出流 按单位分 字节流 字符流 按功能分 节点流 处理流(过滤流) 其他 所有的流继承与这四类流:InputSteam.OutputStream ...

  8. JAVA中IO流总结

    本文是在学习中的总结,欢迎转载但请注明出处:http://blog.csdn.net/pistolove/article/details/42119261 我想你对JAVA的IO流有所了解,平时使用的 ...

  9. Java基础IO流(二)字节流小案例

    JAVA基础IO流(一)https://www.cnblogs.com/deepSleeping/p/9693601.html ①读取指定文件内容,按照16进制输出到控制台 其中,Integer.to ...

随机推荐

  1. [leetcode.com]算法题目 - Restore IP Addresses

    Given a string containing only digits, restore it by returning all possible valid IP address combina ...

  2. 201621123018《Java程序设计》第5周学习报告

    1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 接口.interface.implements.Comparable.Comparator. 1.2 尝试使用思维导图将这些关键 ...

  3. python收集jvm数据

    之前前辈用 java 写的收集 jvm 脚本, 不太方便组内小伙伴维护, 遂用 python 重写了 #!/usr/bin/env python # -*- coding: utf-8 -*- # F ...

  4. CSV Data Set Config设置

    Jmeter参数化常用的两种方法: 1.使用函数助手 2.CSV Data Set Config 本章主要讲解CSV Data Set Config设置 1.Filename:文件名,指保存信息的文件 ...

  5. 设计模式《JAVA与模式》之解释器模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述解释器(Interpreter)模式的: 解释器模式是类的行为模式.给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个 ...

  6. css 图片文字居中

    1.单行文字居中 2.多行文字居中 3.利用background-position:center;的图片居中 4.利用display:table-cell;属性的图片居中 <!DOCTYPE h ...

  7. node.js中的回调

    同步和阻塞:这两个术语可以互换使用,指的是代码的执行会在函数返回之前停止.如果某个操作阻塞,那么脚本就无法继续,这意味着必须等待. 异步和非阻塞:这两个术语可以互换使用,指的是基于回调的.允许脚本并行 ...

  8. POJ 2887

    #include <iostream> #include <string> #define MAXN 2000 using namespace std; struct node ...

  9. 关于使用 IDEA Spring Boot 热部署

    1,POM 中引用 <dependency> <groupId>org.springframework.boot</groupId> <artifactId& ...

  10. vue教程2-04 vue实例简单方法

    vue教程2-04 vue实例简单方法 vue实例简单方法: vm.$el -> 就是元素 vm.$data -> 就是data <!DOCTYPE html> <htm ...