JAVA IO 输入流 输出流笔记(一)

时间:2023-02-24 20:36:48
IO负责数据的传递,也是最容易形成瓶颈的一环,使用IO的情况有很多,大致分为以下几部分:
         ·字节操作(InputStream、OutputStream)
         ·字符操作(Writer、Reader)
         `磁盘操作
         ·控制台操作
           ·网络操作 socket (此类不在java.io包下面)
影响IO操作的要么是传输的数据格式(字符、字节),要么就是传输介质(磁盘、控制台、网络),java.io有很多jar包来解决这个问题。


1、输入流

java io类库可以分为输入流和输出流,输入流来读数据,输出流来写数据;输入流中分字节流的InputStream和字符流的Reader;输出流分字节流的OutputStream和字符流的Writer;

InputStream是字节输入流的超类,她的衍生子类都有read()方法,可读一个字节或者字节数组, 但是read()方法只负责读数据

OutputStream的衍生子类都有write()方法,用来写一个字节或者字节数组;

但是我们一般不来调用这个方法,因为一般我们需要流的时候,并不是简单的用一个类创建一个对象,而是组合多个对象形成一个流,这就是为什么java.io中流比较复杂的原因。



那么输入流读数据一般从哪里读呢?数据来源是什么,一般是如下几个方面:
直接已知子类: AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, InputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream
1、字节数组(我们用一个InputStream做例子,一般都需要将要读入的数据转换成字节数组)
2、字符串
3、文件系统
4、管道系统
5、filter 他可以通过组装其他流来给流提供额外的特性,比如让流必须使用缓存等
5、其他(如网络等)


下面分别介绍下几个输入流:

流名称 作用 构造器参数作用
ByteArrayInputStream 1、她在内存中开辟一个空间作为她的一个缓冲区,读了字节数据放在这个缓冲区里面;
2、你关闭不了她,即使关闭她后,仍然能够使用她的read()方法,而不报错
ByteArrayInputStream(byte[] buf) 
创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组
StringBufferInputStream 1、可以读字符串
2、但是读字符有问题,建议使用StringReader
StringBufferInputStream(String s) 
 创建一个字符串输入流,以从指定字符串读取数据。
FileInputStream 1、读文件 字节文件(img等)、字符文件
2、但是读字符有问题,建议FileReader
FileInputStream(File file) 
要读取的文件
PipedInputStream 1、读数据到输入管道流,并提供给输出管道流
2、不建议两者放在同一个线程,会堵塞
PipedInputStream(PipedOutputStream src) 创建 PipedInputStream,
以使其连接到传送输出流 src。
SequenceInputStream 1、她将多个流按顺序串联起来,一个流一个流的读 SequenceInputStream(InputStream s1, InputStream s2) 
          通过记住这两个参数初始化新创建的 SequenceInputStream
(将按顺序读取这两个参数,先读取 s1 然后读取 s2),以提供从此 SequenceInputStream 读取的字节
FilterInputStream 1、其他流继承他,然后给这些流提供额外的功能,见下表  


继承自filterInputStream的类,他们扩展了如下的功能。
java.io.FilterInputStream
  java.io.BufferedInputStream
 java.io.DataInputStream (implements java.io.DataInput) 
java.io.LineNumberInputStream
 java.io.PushbackInputStream

FilterInputStream及其派生类有两项重要任务:

DataInputStream可以读取各种primitive及String。(所有的方法都以"read"打头,比如readByte( ), readFloat( ))。它,以及它的搭档DataOutputStream,能让你通过流将primitive数据从一个地方导到另一个地方。

  其它的类都是用来修改InputStream的内部行为的:是不是做缓冲,是不是知道它所读取的行信息(允许你读取行号或设定行号),是不是会弹出单个字符。后两个看上去更像是给编译器用的(也就是说,它们大概是为Java编译器设计的),所以通常情况下,你是不大会用到它们的。 

不论你用哪种I/O设备,输入的时候,最好都做缓冲。所以对I/O类库来说,比较明智的做法还是把不缓冲当特例(或者去直接调用方法),而不是像现在这样把缓冲当作特例

流名称
作用
构造器参数作用
DataInputStream 1、可以从基本流中*的读取java的基本类型和string,通过readXXX方法
2、因为前面基本的流都只是读字节数组或者字符串的,读不了int等,必须转换
DataInputStream(InputStream in) 
          使用指定的基础 InputStream 创建一个 DataInputStream。
BufferedInputStream 1、强制使用缓冲区 BufferedInputStream(InputStream in) 
          创建 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用
LineNumberInputStream 1、读当前流数据行号
2、给编译器用的
 
PushbackInputStream 1、她可以讲读出来的数据再放回去
2、编译器用的
 


2、输出流
输出流于输入流对应,输出流主要输出到下面几个部分:
直接已知子类ByteArrayOutputStream(字节数组), FileOutputStream(文件), FilterOutputStream(扩展破坏器), ObjectOutputStream, OutputStream, PipedOutputStream(管道)、控制器

流名称
作用
构造器参数作用
ByteArrayOutputStream 1、她在内存中开辟一个空间作为她的一个缓冲区,要写的字节数据放在这个缓冲区里面;
2、你关闭不了她,即使关闭她后,仍然能够使用她的read()方法,而不报错
ByteArrayOutputStream(byte[] buf) 
创建一个 ByteArrayOutputStream,使用 buf 作为其缓冲区数组
StringBufferOutputStream 这个没有,写字符串不用缓存  
FileOutputStream 1、写文件 字节文件(img等)、字符文件
2、但是写字符有问题,建议FileWriter

FileOutputStream(File file) 
要写的文件

FileOutputStream(File file,boolean append) 
要写的文件 采用追加的方式

PipedInputStream 1、读数据到输入管道流,并提供给输出管道流
2、不建议两者放在同一个线程,会堵塞
 
SequenceInputStream
这个没有,排序交给input了  
FilterOutputStream 1、其他流继承他,然后给这些流提供额外的功能,见下表  


继承自filterOutputStream的类,他们扩展了如下的功能。
java.io.FilterOutputStream
  java.io.BufferedOutputStream
  java.io.DataOutputStream (implements java.io.DataOutput) 
java.io.PrintStream (implements java.lang.Appendable, java.io.Closeable) 



流名称
作用
构造器参数作用
DataOutputStream 1、可以向基本流中写入java基本类型和字符串
2、因为前面基本的流都只是写字节数组或者字符串的,写不了int、boolean等,必须转换
创建一个新的数据输出流,将数据写入指定基础输出流。
BufferedOutputStream
1、以前写数据每次都要调用文件系统,使用缓冲可以先缓冲一部分数据再交给基本流一次性写入。  
LineNumberInputStream 1、读当前流数据行号
2、给编译器用的
 
PushbackInputStream 1、她可以讲读出来的数据再放回去
2、编译器用的
 


下面是一个关于DataInputStream的例子

package test.io.filter;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

/**
* @2012年12月19日10:59:58
* @author sunyz
* DataOutputStream 和DataInputStream 存在的意义:
* 比如你想存储一个float值到文件当中,需要将float值转换成String对象,然后再分解成字节数组才能够存放,使用FileWriter;
* 然而使用DataOutputStream 不用考虑这么多的数据类型,它支持java各种基本类型和String,只需要使用它的writeXXX()方法
* 就可以了,所以很是方便
*
* 同样DataInputStream 只需要使用readXXX()读出来相应的方法,DataInputStream需要的构造参数就是DataOutputStream
*/
public class FilterInputStreamTest {

public static void main(String[] args) {
testOutput();
}

/**
* 现在使用DataOutputStream 测试如何存储float到number.txt文件当中
*/
public static void testOutput(){
String source = "请将我读出来";
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
//dataOutputStream.writeChars(source);
dataOutputStream.writeFloat(12.30f);
dataOutputStream.writeBoolean(false);

ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream);

System.out.println(dataInputStream.available());
System.out.println(dataInputStream.readFloat());
System.out.println(dataInputStream.readBoolean());
byteArrayOutputStream.close();
dataOutputStream.close();


} catch (Exception e) {
e.printStackTrace();
}

}

}

 

3、本身的缺陷:RandomAccessFile

       从类名上看他不是输入io类的,但是他实现了InputStream 和 OutputStream当中的接口,他跟其他IO类相比,有一个很大的功能就是:能够在使用seek()方法在一个文件的任何位置移动,(前提是这个文件长度是已知的),能在任意位置读取和修改这个文件,看起来好像是InputStream和OutputStream两者的结合,他的构造函数中RandomAccessFile(File file,String mode)  mode参数还能设定文件的访问类型,是只读?读写?还是什么的

     文件的读写权限,可以参考SecurityManager.checkRead();权限。认识SecurityManager请参考http://blog.csdn.net/zhoche2008/article/details/7101830

     跟RandomAccessFile类一比较就看出来IO的缺陷出来,比方说我们想象RandomAccessFile一样,随便的访问流中的任意一个位置,这是做不到的,RandomAccessFile虽然可以访问任意位置,但是只限于找文件。

备注:

 1、涉及到字节到字符的转换,一般用InputStreamReader(读字节)

 2、涉及到字符到字节的转换,一般用OutputStreamWriter(写字节)