在学长的要求下,我作为刚进入IT界不到两个月的小白鼠,利用了两天时间制作了一份关于java io包的字节流的ppt,并决定将其写成自己的第一篇博客。大牛看到本文槽点望请及时与作者联系,新人入门不喜勿喷,谢谢。
首先我们来看一看io包中的字节流类库图。
本文将按着接口,InputStream类,OutputStream类,子类实例的顺序进行讲解。
##一 、包中接口 ##
ObjectInput接口:ObjectInput 扩展 DataInput 接口以包含对象的读操作。DataInput 包括基本类型的输入方法;ObjectInput 扩展了该接口,以包含对象、数组和 String 的输出方法。其子接口有:
InputStream
ObjectOutputStream
ObjectInputStream
DataInput接口:用于从二进制流中读取字节,并根据所有 Java 基本类型数据进行重构。同时还提供根据 UTF-8 修改版格式的数据重构 String 的工具。后文出现的实现类有:
DataInputStream
ObjectInputStream
DataOutput 接口:用于将数据从任意 Java 基本类型转换为一系列字节,并将这些字节写入二进制流。同时还提供了一个将 String 转换成 UTF-8 修改版格式并写入所得到的系列字节的工具。后文出现的DataOutput 接口的实现类有:
ObjectOutputStream
DataOutputStream
RandomAccessFile
ObjectOutput 接口:扩展 DataOutput 接口以包含对象的写入操作。DataOutput 包括基本类型的输出方法;ObjectOutput 扩展了该接口,以包含对象、数组和 String 的输出方法。后文出现的ObjectOutput接口实现类有:
ObjectOutputStream
##二、InputStream及其子类##
此抽象类是表示字节输入流的所有类的超类,继承该类的子类能够实现对数据的读取 。InputStream的作用是用来表示那些从不同数据源产生输入的类。
InputStream读取数据源及其对应子类:
1)字节数组 – ByteArrayInputStream
2)String对象 – StringBufferInputStream
3)文件 – FileInputStream
4)“管道”:从一端输入,从另一端输出 – PipedInputStream
5)一个由其他种类的流组成的序列 – ObjectInputStream
6)其他数据源,如音频文件 – AudioInputStream
三、OutputStream及其子类##
OutputStream类别的类决定了输出所要去的目标,这些目标包括及其对应子类:
1)字节数组 – ByteArrayOutputStream
2)文件 – FileOutputStream
3)“管道” – PipedOutputStream
四、应用子类实例##
- 读取音频文件的AudioInputStream
需求说明:现在我们要用AudioInputStream 读取C:\Users\lenovo\Music目录下的音频文件”逃跑计划 - 夜空中最亮的星.wav“。
File f = new File("C:\\Users\\lenovo\\Music\\逃跑计划 - 夜空中最亮的星.wav");
byte[] b = new byte[1024];
try(AudioInputStream as = AudioSystem.getAudioInputStream(f);){
//将音频文件读取字节数组中
as.read(b);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(b[0]);
注意:AudioInputStream读取的音频文件必须是wav格式的。
备注:本文为了验证成功读取文件使用System.out.println(b[0])查看b中的数据。
2.读取字节数组的ByteArrayInputStream
需求说明:现在我们要用ByteArrayInputStream 读取”F:\1.txt文件”。
byte buf[] = new byte[1024];
byte b[] = new byte[1024];
// 创建一个 ByteArrayInputStream,使用 b作为其缓冲区数组。
try(InputStream is = new FileInputStream("C:/Users/lenovo/Music/Justin Bieber - Love Yourself.mp3");
ByteArrayInputStream bais = new ByteArrayInputStream(b);)
{
is.read(b);
//将数据此输入流读入 byte数组
bais.read(buf);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(buf[0]);
3.写入字节的ByteArrayOutputStream
需求说明:现在我们要用ByteArrayOutputStream 接收输入流中的数据,然后将数据写入字节数组。
int temp = 0;
//创建输入输出流对象
try(InputStream is = new FileInputStream("C:/Users/lenovo/Music/Justin Bieber - Love Yourself.mp3");
ByteArrayOutputStream baos = new ByteArrayOutputStream())
{
//将输入流中的数据写入输出流
while((temp=is.read())!=-1){
baos.write(temp);
}
//将输出流中的数据导出到字节数组中
byte[] b = baos.toByteArray();
System.out.println(b[0]);
} catch (Exception e) {
e.printStackTrace();}
4.读取文件的FileInputStream
需求说明:现在我们要用FileInputStream 将文件中的数据读入字节数组。
byte[] b = new byte[1024];
try(InputStream is = new FileInputStream("F:/1.txt"))
{
//将文件中的数据读入字节数组
is.read(b);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(b[0]);
5.将数据写入文件的FileOutputStream
需求说明:将”1.txt“文件复制到一个指定路径的新文件”2.txt“中。
int temp = 0;
//创建文件读取输出流
try(InputStream is = new FileInputStream("F:/1.txt");
FileOutputStream fos = new FileOutputStream("F:/3.txt"))
{
while((temp=is.read())!=-1){
fos.write(temp);
}
} catch (Exception e) {
e.printStackTrace();
}
6.接受写入管道输出流的所提供的数据字节的PipedInputStream
需求说明:利用PipedInputStream读取管道输出流中的数据。
//创建一个管道输入流
PipedInputStream pis = new PipedInputStream();
byte a[] = new byte[]{1,2,3,4,5,6};
byte b[] = new byte[1024];
//创建一个管道输出流
PipedOutputStream pos = new PipedOutputStream();
//将字节数组写入管道输出流
try{ //将输出流管道与输入流管道连接,不连接将抛出IO
pos.connect(pis);
pos.write(a,0,5);
//刷新管道输入流
pos.flush();
//读取管道输出流中的数据
pis.read(b);
System.out.println(b[0]);
} catch (IOException e) {
e.printStackTrace();
}finally{ //关闭管道输入流和管道输出流
try { pos.close();
pis.close();
} catch (Exception e) {
System.out.println("发生IO异常!");}}
7.将数据写入管道的PipedOutputStream
需求说明:将字节数组写入管道输出流PipedOutputStream中。代码展示如上例。
8.将其他输入流逻辑串联,依次读取的SequenceInputStream
需求说明:将两个输入流连接在一起,依次读取两个输入流的数据。
byte[] b = new byte[1024];
try(InputStream is1 = new FileInputStream("F:/1.txt");
InputStream is2 = new FileInputStream("F:/2.txt");
//创建SequenceInputStream对象,将两个输入连接
SequenceInputStream sis = new SequenceInputStream(is1,is2);)
{
//依次读取两个输入流
sis.read(b);
} catch (IOException e) {
e.printStackTrace();}
System.out.println(b[0]);
9.从文件中读取类的ObjectInputStream
需求说明:将ObjectOutputStream向文件中写入的类利ObjectInputStream读取出来。
FileInputStream fis = new FileInputStream("F:/1.tmp");
//创建读取类的ObjectInputStream对象
ObjectInputStream ois = new ObjectInputStream(fis);
FileOutputStream fos = new FileOutputStream("F:/1.tmp");
//创建写入类的ObjectOutputStream对象
ObjectOutputStream oos = new ObjectOutputStream(fos);
//利用writeObject()方法向指定文件写入类
oos.writeObject("Today");
oos.close();
//利用readObject()方法读取指定文件的类返回的是object类,所以要进行强转
String time =(String)ois.readObject();
ois.close();
System.out.println(time);
10.向指定文件写入类的ObjectOutputStream
需求说明:利用ObjectOutputStream向文件中写入类。展示代码入上例。
11.StringBufferInputStream类现已过时在此不做使用说明。
12.FilterInputStream类展开,对其及其子类进行详细说明。
FilterInputStream包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。FilterInputStream 的子类可进一步重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。FilterInputStream的子LineNumberInputStream已过时不做说明
对FilterInputStream 的子类进行说明。
(1)缓冲输入以及支持 mark 和 reset 方法的BufferedInputStream
需求说明:利用BufferedInputStream接受键盘输入的数据。
byte b[] = new byte[1024];
try( BufferedInputStream bis = new BufferedInputStream(System.in);
DataInputStream dis = new DataInputStream(bis);)
{ //在输入流处做好标记,并保留1024位
dis.mark(1024);
//将键盘输入的数据读入字节数组b中
dis.read(b);
String a1 = new String(b,0,b.length);
System.out.println(a1);
//重新回到之前的标记处,再次读取数据
dis.reset();
dis.read(b);
String a2 = new String(b,0,b.length);
System.out.println(a2);
} catch (IOException e) {
e.printStackTrace();}
(2)校验和可用于验证输入数据的完整性的CheckedInputStream
需求说明:验证数据的完整性后,将数据读入数组。
byte b[] = new byte[1024];
//指定的校验和 ,Adler32是可用于计算数据流的 Adler-32 校验和的类
Checksum c = new Adler32();
try(InputStream is = new FileInputStream("F:/1.txt");
CheckedInputStream cis = new CheckedInputStream(is, c))
{
//返回当前的校验和值
c.getValue();
//将数据读入字节数组
cis.read(b);
cis.close();
System.out.println(b[0]);
} catch (Exception e) {
e.printStackTrace();}
(3)读取加密数据的CipherInputStream
需求说明:利用CipherInputStream将加密数据读入。
InputStream is = null;
//service为具体的值
try { is = new FileInputStream("service");
//实例化KeyGenerator对象,指定一个算法 ,DES是一种转换名称,其他CBC、PKCS5Padding
KeyGenerator kg = KeyGenerator.getInstance("DES");
//生成SecretKey对象
SecretKey secrekey = kg.generateKey();
//实例化Cipher对象
Cipher c = Cipher.getInstance("DES");
//初始化Cipher对象,用于解密操作。
c.init(Cipher.DECRYPT_MODE,secrekey);
CipherInputStream cis = new CipherInputStream(is, c);
//使用DataInputStream对象包装CipherInputStream对象
DataInputStream dis = new DataInputStream(cis);
//将数据读入到字节数组
String utf = dis.readUTF();
System.out.println(utf);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {i s.close();
} catch (IOException e) {
e.printStackTrace();}}
(4)使用通过流的位更新关联消息摘要的透明流DigestInputStream
需求说明:利用DigestInputStream将数据读入,并带有消息摘要。
//使用指定的输入流和消息摘要创建一个摘要输入流。
InputStream is;
MessageDigest md;
DigestInputStream dis = null;
byte b [] = new byte[1024];
try { is = new FileInputStream("F:/1.txt");
//此 MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法
md = MessageDigest.getInstance("MD5");
dis = new DigestInputStream(is, md);
//读取字节并更新消息摘要(如果开启了摘要功能)
dis.read(b);
System.out.println(b[0]);
} catch (Exception e) {
e.printStackTrace();
}finally{ try {
dis.close();
} catch (IOException e) {
e.printStackTrace();}}
(5)监视读取某些 InputStream 进度的ProgressMonitorInputStream
需求说明:利用DigestInputStream将数据读入,并进行监视。
InputStream is;
ProgressMonitorInputStream pmis = null;
byte b[] = new byte[1024];
try{
is = new FileInputStream("F:/1.txt");
String a = "Reading"+"F:/1.txt";
//构造一个对象,以监视输入流的进度。
pmis = new ProgressMonitorInputStream(new Button(), a, is);
//重写 FilterInputStream.read,以读取之后更新进度监视器。
pmis.read();
System.out.println(b[0]);
} catch (Exception e) {
e.printStackTrace();
}finally{ try {
pmis.close();
} catch (IOException e) {
e.printStackTrace();}}
(6)拥有推回和取消读取字节能力的PushbackInputStream
需求说明:利用PushbackInputStream将数据读入,并将数据推回,再次读取。
byte b[] = new byte[1024];
int num = 1;
try(InputStream is = new FileInputStream("F:/1.txt");
PushbackInputStream pis = new PushbackInputStream(is);)
{
pis.read(b);
System.out.println(b[0]);
//推回一个 byte数组:将其复制到推回缓冲区之前
pis.unread(num);
pis.read(b);
System.out.println(b[0]);
} catch (Exception e) {
e.printStackTrace();}
(7)允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型的DataInputStream
需求说明:利用DataInputStream将数据读入。
byte[] b = new byte[1024];
try(InputStream is = new FileInputStream("F:/2.txt");
DataInputStream dis = new DataInputStream(is);)
{
//从输入流中读取字节,并将它们存储在缓冲区数组 b中
dis.read(b);
System.out.println(b[0]);
} catch (Exception e) {
e.printStackTrace();
}
(8)FilterInputStream下的特殊子类InflaterInputStream
InflaterInputStream为解压缩 “deflate” 压缩格式的数据实现流过滤器,其两个子类分别为:读取 ZIP 文件格式的文件实现输入流过滤器ZipInputStream和
读取 GZIP 文件格式的压缩数据实现流过滤器GZIPInputStream。
a.为读取 ZIP 文件格式的文件实现输入流过滤器的ZipInputStream
ZipInputStream可以得到压缩实体,但得不到压缩实体的流,流存贮在ZipEntry对象中。所以要想获得文件相对应的数据必须,将对应文件的ZipEntry对象创建出来。
每个压缩文件中都会存在多个子文件,每个子文件在java中ZipEntry来表示。
ZipInputStream对应的输出流类ZipOutputStream。
GZIPInputStream用于对GZIP格式的文件进行操作,GZIP 格式的文件用于UNIX系统的文件压缩,本ppt就不做详解,其对应输入流为DZIPOutputStream。对于文件的处理机制类似于ZipInputStream。
现在我们来看看利用ZipInputStream如何处理文件。
try(InputStream is = new FileInputStream("F:/2.txt");
ZipInputStream zis = new ZipInputStream(is);
FileOutputStream fos = new FileOutputStream(new File("F:/2.zip"));
ZipOutputStream zos = new ZipOutputStream(fos); )
{ //设置ZipEntry对象
ZipEntry ze = new ZipEntry("F:/2.txt");
// 设置ZipEntry对象
zos.putNextEntry(ze);
int temp = 0 ;
//将要压缩的文件利用ZipInputStream对象读入输出流中
while((temp=zis.read())!=-1){ // 读取内容
zos.write(temp) ; // 压缩输出 }
System.out.println(ze.getName());
} catch (Exception e) {
e.printStackTrace();
}
b.对jar文件进行处理的特殊类:JarInputStream
jar压缩的支持类包括:
1)jar压缩输出流:JarOutputStream
2)jar压缩输入流:JarOutputStream
3)jar文件:JARFILE
4)jar实体:JAREntry
接下来对jar压缩进行举例说明。
//创建输入输出流
try( JarInputStream jis = new JarInputStream(new FileInputStream("F:/2.txt"));
JarOutputStream jos = new JarOutputStream(new FileOutputStream("F:/2.jar")))
{
//创建对应的JarEntry对象
JarEntry ze = new JarEntry("F:/2.txt");
//向输出流中设置ZipEntry对象
jos.putNextEntry(ze);
//将文件压缩输出
int temp = 0;
while((temp=jis.read())!=-1){
jos.write(temp);
}
} catch (Exception e) {
e.printStackTrace();
}
注:该实例直接使用FileInputStream类,未使用JarFile类
(9)对文件进行随机读取的RandomAccessFile
//public RandomAccessFile(File file, String mode)
//该构造方法创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
//mode 参数指定用以打开文件的访问模式
File f = new File("F:/1.txt");
try(RandomAccessFile raf = new RandomAccessFile(f,"rw");)
{
//随机读取文件中的一个字节
int num = raf.read();
System.out.println(num);
} catch (Exception e) {
e.printStackTrace();
}
##五.作者总结 ##
通过写作该本的制作收获以下心得体会:
1、在进行流操作时,最后一定要将流关闭。该ppt中的实例,作者根据不同的情况,采用了不同的关流方法,包括java7中的Try-With-ResourcesStatement格式。
2、每个特定流的类,可能都有它的特定格式,理解了这种格式,有利于对流的运用。
3、基本上每个特定的InputStream类都有对应的OutputStream类,其实不同类在文件的读取和写入上都存在共同点。
备注:
FilterOutputStream中的子类并未挨个展开,其原理和使用与其他的OutputStream一致。