Java I/O学习(一)
写作目的
自学Java,Java中流的概念比较复杂,故专门作一整理。期望开始学习的童鞋,看完本文后对Java流有一个大致的认识。主要分三个小篇:
一、概述、输入/输出字节流
二、输入/输出字符流、装饰者模式与处理流
三、其他
本文首先大致介绍以下流的概念和分类,然后介绍字节流的接口,最后介绍一些三种常用的字节流,并举例说明它们的用法。
一、什么是流

首先,给一个图,给大家一个感性的认识。大家至少接触过面向对象语言,在面向对象语言中讲到输入输出(I/O)时,一般都是流。那什么是流呢?你能准确描述一下吗?其实我也不能准确描述描述,下面是我的理解。首先说说IO,IO就是将数据从一个地方搬运到另一个地方,如从一个文件运到内存中,从一台机器运到另一台机器。再来说说流,流就是隐藏这一搬运细节的一个对象(或者说将搬运细节封装起来了)。如上图所示,流对象就像桥一样,连接源数据和目标存放位置,我们程序员呢,什么都不用管,只要将源数据按照流对象规定的格式存到流对象中或从流对象读出来。
二、Java中的流
每学一门编程语言,I/O总是很头疼的一块,虽然我一直用C++写代码,但对C++的流我也没有搞懂。像控制结构、基本数据类型、运算类型等等一般都是相同的,但是流在不同的语言中会有很大差别。因为是自学,所以就把它弄清楚一些。JDK本身提供了丰富的流类型。我们首先用思维导图的方式来将这些类整理一下:
是不是很壮观,先大体上说下Java流的分类:
按流向分,可分为输入流和输出流(输入/输出是针对CPU而言的);
按处理数据的类型,可字节流和字符流(一般字节流就够用了,涉及到文本编码,尤其是非ASCII编码的会用到字符流)。在此,要强调的一点:磁盘上存储的所有数据都是面向字节的,字符只存在程序(或者说内存)中。
- 按功能分,可分为节点流和处理流。节点流提供基本功能,处理流提供扩展功能,增加性能。
所有这些类中,最重要的就是InputStream和OutputStream,接着是Reader和Writer。首先来详细介绍以下InputStream的接口。
2.1 InputStream类提供的接口
接口一、从流中读入一个字节的数据

上面这个方法是InputStream唯一的抽象方法,子类必须实现这一方法,其功能是读入一个字节的数据。不同的输入流(有不同的数据源),读入的方式当然是不一样的,接下来要介绍的几个接口都依赖于这一接口。此接口返回值有两种可能:(1) 读到字节的值; (2) -1表示已经读到流的结束。
接口二、从流中读入若干个字节

这个函数是从流中读入若干字节到缓存数组b[]中,返回值也有两种情况:
(1) 实际读到字节数组b中的字节数(可能<b.length);
(2) -1,已经到流的结尾啦,没有字节可读了!
一般而言,上述两个函数是我们在使用输入流时,最常用的两个函数。另外,JDK还给我们提供了另一个更为灵活的读入若干字节的接口:

这个接口与上一个接口的功能是类似的,只是增加了off和len两个参数,使用户可以指定读入字节的起始位置和长度。如果len + off > b.length,会抛出一个IndexOutofBoundsException异常。
2.2 OutputStream类提供的接口
接下来,介绍输出流的接口。OutputStream的接口与InputStream的接口是一一对应的。你有read一个字节,那我就有write一个字节;你有read若干个字节,那我就有write若干个字节。接口如下(不做详细介绍了):
public abstract void write(int b) throws IOException;
public void write(byte b[]) throws IOException;
public void write(byte b[], int off, int len) throws IOException;
2.3 字节流的派生类及作用

2.4 流的使用
下面通过几个实例来看看第3节介绍的三种流的用法。
1. 文件输入流
public static void main(String args[]) throws IOException {
// 定义文件输入流
FileInputStream fis = new FileInputStream("test.txt");
// 定义读入缓存字节
byte buf[] = new byte[1024];
// 使用read接口读入
fis.read(buf);
// 输出读入的字节
System.out.println(new String(buf));
}
【注】这里读入的buf字节数组,将其按系统默认字符集编码转为String字符串,然后输出。若文件的字符集编码与系统默认字符集编码不一致,则需要在构造String指定编码,否则可能出现乱码。
2. 字节数组输入流
前面已经指出,该流主要用于接收并解析网络数据,在单机上没啥意思。另外,需要配合处理流(如:DataInputStream)一起使用,在这里我们通过一个简单的例子来演示一下。
public static void main(String args[]) throws IOException {
// 定义输入缓冲区,这部分内容通常由网络传输过来的。
String sBuf = new String("ByteArrayInputStream Test.");
byte buf[] = sBuf.getBytes();
// 定义输入字节数组流
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
// 读入其中的8个字节并输出
byte[] obuf = new byte[8];
bais.read(obuf);
System.out.println(new String(obuf));
// 再次强调:上述三行代码仅仅演示,一般字节数组流不单独使用。
}
3. 管道流
配合使用,最好在线程中使用,便于线程的通信。为了演示,首先派生两个线程类,如下:
//实现两个线程类
class ThreadRead extends Thread { private PipedInputStream mPis = null; public ThreadRead(PipedInputStream pis) {
mPis = pis;
} // 读取管道流内容并输出
public void run() {
byte[] buf = new byte[100];
try {
mPis.read(buf);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(new String(buf));
}
} class ThreadWrite extends Thread { PipedOutputStream mPos = null; public ThreadWrite(PipedOutputStream pos) {
mPos = pos;
} public void run() {
String s = new String("你好!PipedOutputStream.");
try { mPos.write(s.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
主函数如下:
public class PipedStreamDemo01 {
public static void main(String args[]) {
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = null;
try {
pis = new PipedInputStream(pos);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} Thread th1 = new ThreadRead(pis);
Thread th2 = new ThreadWrite(pos); th2.start();
th1.start();
}
三、小结
到此,字节流大致介绍完毕。
Java I/O学习(一)的更多相关文章
- JAVA GUI编程学习笔记目录
2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...
- 一位资深程序员大牛给予Java初学者的学习路线建议
java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是我你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈 ...
- java并发编程学习: ThreadLocal使用及原理
多线程应用中,如果希望一个变量隔离在某个线程内,即:该变量只能由某个线程本身可见,其它线程无法访问,那么ThreadLocal可以很方便的帮你做到这一点. 先来看一下示例: package yjmyz ...
- 回答阿里社招面试如何准备,顺便谈谈对于Java程序猿学习当中各个阶段的建议
引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力不是很好,不像一些记忆力强的人,面试完以后,几乎能把自己和面试官的对话都给记下来.LZ自己当初面试完以后,除了记住一些聊过的知识点以外,具体的内容 ...
- Java程序员学习之路
1. Java语言基础 谈到Java语 言基础学习的书籍,大家肯定会推荐Bruce Eckel的<Thinking in Java>.它是一本写的相当深刻的技术书籍,Java语言基础部分基 ...
- 老鸟谈谈JAVA EE的学习
老鸟谈谈JAVA EE的学习 因为出差和项目的原因,有将近一个月的时间没有更新博客了,今天终于得闲,和兄弟们分享一下JAVA EE的学习心得.书中带过,直入主题,下面我们首先看看什么是JAVA EE. ...
- Java虚拟机JVM学习07 类的卸载机制
Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...
- Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论
Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...
- Java虚拟机JVM学习05 类加载器的父委托机制
Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...
- Java虚拟机JVM学习04 类的初始化
Java虚拟机JVM学习04 类的初始化 类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值. 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行初始 ...
随机推荐
- Javascript 迭代法实现数组多条件排序
多条件排序可能有很多种思路,效率也各不相同,我的方法可能只适合自己用,毕竟目的是为了实现功能,所以采用了最笨的方法,不过效果还是很理想的,经过多次测试,6列1000行数据,平均排序时间大约是:28ms ...
- 02_Jquery_02_元素选择器
[简述] 元素选择器就是通过元素名来查询元素 $("elementName")这里就可以通过元素名来获取jquery元素了. 但与id选择器不同的是,名称相同的元素有很多,所以获取 ...
- Nuage SDN
Nuage推出纯软件解决方案虚拟化业务平台(VSP)由三部分组成:虚拟化业务目录(VSD).虚拟化业务控制器(VSC)和虚拟路由与交换(VRS). VSD是业务/IT策略引擎,可提供业务模板与分析,每 ...
- 封装一个自己的 Ajax小框架
框架代码如下: // 使用封装方法的人只关心提供http的请求方法,url地址,数据,成功和失败的回调方法 // 类的构造定义,主要职责就是新建出 XMLHttpRequest 对象 var MyXM ...
- MySQL常见错误类型
MySQL常见错误类型:1005:创建表失败1006:创建数据库失败1007:数据库已存在,创建数据库失败1008:数据库不存在,删除数据库失败1009:不能删除数据库文件导致删除数据库失败1010: ...
- leetcode problem 6 ZigZag Conversion
The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like ...
- php date('Y')
date('Y')默认是y-12-01 date('Y-01')!!!才是我需要的
- OS概论2
实时系统 实时即表示及时,实时计算可以定义为这样一类计算:系统的正确性,不仅由计算的逻辑结果来确定,而且还取决于产生结果的时间.事实上,实时系统最主要的特征,是将时间作为关键参数,它必须对所接收到的某 ...
- 阿里云主机建立SWAP分区脚本
工具:add_swap.sh 所有执行的脚本都需要root身份来执行,执行方法:以root身执行命令:bash xxx.sh 功能:自动检测系统swap分区大小,交换分区大小不合理则自动新增并挂 ...
- 学习TextKit框架(上)
TextKit简介 在iOS7之前我们要实现图文混排要使用CoreText,iOS6时有了Attribute string 可以解决一些简单的富文本需求.直到iOS7 苹果推出了TextKit,Tex ...