什么是IO流呢,换句话来说什么是流呢?
我们来看下什么是流。
流简介
Java把这些不同类型的输入、输出源抽象为流(stream),用统一接口来表示,从而使程序简单明了。在Java类库中,IO部分的内容是很庞大的,因为它涉及的领域很广泛:标准输入输出,文件的操作,网络上的数据流,字符串流,对象流,zip文件流 等等
Java对数据的操作是通过流的方式,IO流用来处理设备之间的数据传输,上传文件和下载文件,Java用于操作流的对象都在IO包中。
流分类
我们在java中,将流分类的
按数据流的方向不同:输入流In,输出流Out。
按处理数据单位不同:字节流,字符流。
字节流:数据流中最小的数据单元是字节。
顶层为抽象类
InputStream OutputStream
字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节。
顶层为抽象类
Writer Reader
对象流
按功能不同:节点流,处理流。
(1)程序用于直接操作目标设备所对应的类叫节点流。
(2)程序通过一个间接流类去调用节点流类,以达到更加灵活方便地读写各种类型的数据,这个间接流类就是处理流。**
我们来看图让我们对这个更加清晰一些
流体系
这篇文章我们来认识一些字节流吧
字节流
字节流
常用方法
int read()每次读一个字节
int read(char cbuf[])读取cbuf指定数组大小的字节数装载到cbuf中【最后一次有多少读多 其它位置为默认值】
int read(char cbuf[], int offset, int length) 读取数据装载到cbuf数组中,指定开始位置和长度
int available( );调用此方法表还有多少数据可以读取
close( );关闭
字符流
常用方法
void write(int)写数据
void close()关闭流
void flush()强制输出
我们来看下字节流最简单的一个流
文件输入输出流FileInputStream
上面的是字节流的文件输入输出流的案例 是不是很简单的
接下来我们来看下稍微加点难度的
缓冲流
BufferedInputStream
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。
特点:
缓冲区、处理流
不多说我们直接上代码
package byte_stream;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
/**
* 缓冲输入流
* @author wenber
*
*/
public class TestBufferedInputStream {
public static void main(String[] args) {
FileInputStream fis=null;
BufferedInputStream bis=null;
try {
//创建节点流
fis=new FileInputStream("d:/test/readme.txt");
//创建处理流[带缓冲]
bis=new BufferedInputStream(fis);
//标记位置
bis.mark(0);
//流中还有多少字节可读
System.out.println(bis.available());
//读取数据
System.out.println("第一次读取="+(char)(bis.read()));
//流中还有多少字节可读【每读一次少一次】
System.out.println(bis.available());
//==================================重置
bis.reset();//回到标记的位置 重新开始
System.out.println("重新开始==="+(char)(bis.read()));
//跳过指定的字节数 进行读取
bis.skip(1);
System.out.println("skip==="+(char)(bis.read()));
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(fis!=null)fis.close();
if(bis!=null)bis.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
我们来看下字节数组输入输出流
ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含从流中读取的字节。内部计数器跟踪 read 方法要提供的下一个字节。 关闭 ByteArrayInputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。
看代码
package byte_stream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* 测试ByteArray流
* @author wenber
*
*/
public class TestByteArray {
public static void main(String[] args) {
try {
String msg="abcdefg";
//将字符串转成字节数组
byte[] buf=msg.getBytes();
//ByteArrayInputStream bis=new ByteArrayInputStream(buf);
//1:数据 字节数组 2从哪开始【offset偏移量】 3:长度
ByteArrayInputStream bis=new ByteArrayInputStream(buf,4,2);
//添加标记
bis.mark(0);
System.out.println(bis.read());
//重置
bis.reset();
//关闭了流 仍然可以进行读取
bis.close();
System.out.println(bis.read());
System.out.println("是否支持 mark/reset="+bis.markSupported());
} catch (IOException e) {
e.printStackTrace();
}
}
}
SequenceInputStream合并流
SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
package byte_stream;
import java.io.FileInputStream;
import java.io.SequenceInputStream;
import java.util.Vector;
/**
* 测试合并流
* @author wenber
*
*/
public class TestSequenceStream {
public static void main(String[] args) {
testOne();
testTwo();
}
/**
* 合并多个
*/
private static void testTwo() {
SequenceInputStream sis=null;
//用来存入所有的流
Vector<FileInputStream> vector=new Vector<FileInputStream>();
try {
vector.add(new FileInputStream("d:/test/a.txt"));
vector.add(new FileInputStream("d:/test/b.txt"));
vector.add(new FileInputStream("d:/test/c.txt"));
//合并多个流【将vector集合中的所有流合并】
sis=new SequenceInputStream(vector.elements());
int m;
while((m=sis.read())>0){
System.out.println((char)m);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
for (int i = 0; i < vector.size(); i++) {
if(vector.get(i)!=null)vector.get(i).close();
}
if(sis!=null)sis.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
/**
* 合并两个
*/
private static void testOne() {
FileInputStream fis1=null;
FileInputStream fis2=null;
SequenceInputStream sis=null;
try {
fis1=new FileInputStream("d:/test/a.txt");
fis2=new FileInputStream("d:/test/b.txt");
//合并上面的两个流
sis=new SequenceInputStream(fis1, fis2);
int m;
while((m=sis.read())>0){
System.out.println((char)m);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(fis1!=null)fis1.close();
if(fis2!=null)fis2.close();
if(sis!=null)sis.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
package byteio;
import java.io.FileInputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;
/**
* 测试合并流
* @author wenber
*
*/
public class TestSequenceInputStream {
public static void main(String[] args) {
try {
FileInputStream fis1=new FileInputStream("d://io/a.txt");
FileInputStream fis2=new FileInputStream("d://io/b.txt");
//创建集合
Vector<FileInputStream> vector=new Vector<FileInputStream>();
//将流添加到集合中
vector.add(fis1);
vector.add(fis2);
//将流转为枚举对象
Enumeration<FileInputStream> enums=vector.elements();
//SequenceInputStream seq=new SequenceInputStream(fis1, fis2);
//将枚举中的流 合并成一个序列流
SequenceInputStream seq=new SequenceInputStream(enums);
int a;
while((a=seq.read())>0){
System.out.println((char)a);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
InputStreamReader桥接流
InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可要考虑在 BufferedReader 内包装 InputStreamReader。
我们看代码
package char_stream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
/**
* 字节转字符的桥接流
* @author wenber
*
*/
public class TestInputStreamReader {
public static void main(String[] args) {
FileInputStream fis=null;
InputStreamReader isr=null;
try {
fis=new FileInputStream("d:/test/readme.txt");
//将FileInputStream字节流传入InputStreamReader字符桥接流
isr=new InputStreamReader(fis,"UTF-8");
int m;
while((m=isr.read())>0){
System.out.println((char)m);
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
if(fis!=null)fis.close();
if(isr!=null)isr.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
这个是字节流中的几种必将常用的流,希望可以帮助大家能更好的理解
其实只要把字节流基本搞懂了,字符流是差不多的。
我们下篇文章来看看字符流是怎么去实现的和IO流的序列化以及反序列化
有哪些地方不是很好的希望大家可以在下面评论提示一下哦