IO流

InputStream字节输入流,outPutStream字节输出流

1)InputStream类提供了一系列读取数据有关的方法。它们都是抽象类,不能被实列化。

int read():从输入流中读取一个8位的bit,把它转换成一个0-255的整数,返回这一整数。列如:如果读到的字节为9,则返回9,如果读到的字节为-9,则返回247。如果输入流的结尾,则返回-1。

int read(byte[] byte):从输入流读取若干字节,把他们保存到参数b指定的字节数组中,返回的整数表示读取的字节数。如果输入流的结尾,则返回-1。

int read(byte[],int off ,int len):从输入流读取若干字节,把他们保存到参数B指定的字节数组中。参数off指定在字节数组中开始保存数据的起始下标,参数len指定读取的字节数目。返回的整数表示实际读取的字节数。如果读到输入流的结尾,则返回-1。

以上第一个read()方法从输入流读取一个字节,其余两个read方法从输入流批量读取若干字节。

2)outputStream类提供了一系列读取数据有关的方法。

void write(int b):向输入流写入一个字节。

void write(byte[] b):把参数b指定的字节数组中的所有字节写到输出流。

void write(byte[] b, int off, int len):把参数b指定的字节数组的若干字节写到输出流,参数off指定字节数组的起始下标,从这个位置开始输出由参数len指定数目的字节。

以上第一个write方法向输入流写入一个字节,而其余两个write方法向输出流批量写入若干字节。在向文件或控制台写数据时,采用后面两个write方法可以减少进行物理写文件或控制台的次数。

子类实现

1)字节数组输入流: ByteArrayInputStream类

ByteArrayInputStream从内存中的字节数组中读取数据,因此它的数据源是一个字节数组。这个类的构造方法包括。

ByteArrayInputStream(byte[] b):参数buff指定字节数组类型的数据源。

ByteArrayInputStream(byte[] b, int off, int len):参数buf指定字节数组类型的数据源,参数off指定从字节数组中开始读取数据的起始下标位置,len指定从数组中读取的字节数。

ByteArrayInputStream参考适配器设计模式

类似字节数组输出流: ByteArrayOutStream

2)文件输入流:FileInputStream

FileInputStream从文件中读取数据,它有以下构造方法。

FileInputStream(File file) 参数file指定文件数据源。

FileInputStream(String name) 参数name指定文件数据源。在参数name中包含文件路径信息。

类似的有文件输出流:FIleOutputStream

3)管道输入流:PiedInputStream

PipedInputStream PipedOutputStream进行多线程消息通信。(没什么人用这种方法)

首先写ReadData和WriteData两个工具类,分别利用PipedInputStream PipedOutputStream进行读写操作。

ReadData(read()方法是阻塞式的)

public class ReadData {
    public void readMethod(PipedInputStream input ){
        System.out.println("开始read:");
        byte[] byteArray = new byte[1000];
        int len;
        try {
            //len读入缓冲区的字节总数
            len = input.read(byteArray);        
            while(-1!=len){
                String newData = new String(byteArray,0,len);
                System.out.print(newData);
                len=input.read(byteArray);
            }
            System.out.println();
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
View Code

WriteData

public class WriteData {
    public void writeMethod(PipedOutputStream out){
        try {
            System.out.println("开始write:");
            String outData = ("写数据的内容");
            out.write(outData.getBytes());
            System.out.print(outData);
            System.out.println();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
View Code

开一个读的线程(因为read()方法阻塞 如果没有数据会一直等待)

public class ThreadRead extends Thread{
    private ReadData readData;
    private PipedInputStream input;
    
    public ThreadRead(javaee.net.cn.thread.mythread.ReadData readData,
            PipedInputStream input) {
        super();
        this.readData = readData;
        this.input = input;
    }
    @Override
    public void run(){
        readData.readMethod(input);
    }
}
View Code

开一个写的线程

public class ThreadWriter  extends Thread{
    private WriteData writeData;
    private PipedOutputStream out;
    
    public ThreadWriter(WriteData writeData, PipedOutputStream out) {
        super();
        this.writeData = writeData;
        this.out = out;
    }
    
    @Override
    public void run(){
        writeData.writeMethod(out);
    }
}
View Code

测试:

public class Run {
    public static void main(String[] args) throws Exception {
        WriteData writeData = new WriteData();
        ReadData readData = new ReadData();
        PipedOutputStream out = new PipedOutputStream();
        PipedInputStream input = new PipedInputStream();
        out.connect(input);
        ThreadRead threadRead = new ThreadRead(readData,input);
        threadRead.start();
        Thread.sleep(2000);
        ThreadWriter threadWriter = new ThreadWriter(writeData,out);
        threadWriter.start();
    }
}
View Code

过滤输入流FilterInputStream(装饰者设计模式)

InputStream类声明的read()方法按照流中字节的先后顺序读取字节,FileInputStream和ByteArrayInputStream等具体的输入流都按照这种方式读数据。

假如希望进一步扩展读数据的功能,一种方式是创建FileInputStream等输入流的子类,但这样会大大增加输入流类的数目,使输入流的层次结构更加复杂;

还有一种方式是创建输入流的装饰器,它本身继承了InputStream类,还可以用来装饰其他的输入流类。I/O类库中的FilterInputStream类就是一种装饰器。他有几个子类,分别用来扩展输入流的某一功能。

装饰器设计模式

1)BufferedInputStream

BufferedInputStream类覆盖了被装饰的输入流的读数据行为,利用缓冲区来提高读数据的效率。BufferedInputStream类先把一批数据读入到缓冲区,

接下来read()方法只需从缓冲区内获取数据,这样就能减少物理性读取数据的次数。

BufferedInputStream(InputStream  in , int size)构造方法中参数in指定被需要被装饰的输入流,参数size指定缓冲区的大小,以字节为单位。

当数据源为文件时,可以用BufferedInputStream来装饰输入流,从而提高IO的操作效率。列如在以下程序代码中,文件输入流先被BufferedInputStream装饰。

在被DataInputStream装饰。

 InputStream in1 = new FileInputStream("D:\\text.txt");
 BufferedInputStream in2 = new BufferedInputStream(in1);//装饰文件输入流
 DataInputStream in = new DataInputStream(in2);//装饰缓冲输入流

利用字节数组缓冲区快速进行文件复制

    public  void test2() throws Exception {
        Long startTime=System.currentTimeMillis();
        for(int i=0;i<10;i++){
            InputStream ins = new FileInputStream(startPath);    
            OutputStream out = new FileOutputStream(endPath);
            BufferedInputStream bin = new  BufferedInputStream(ins);
            BufferedOutputStream bout = new BufferedOutputStream(out);
            byte[] buff = new byte[2048];
            while (-1 != (bin.read(buff))) {
                bout.write(buff);
            }
            ins.close();
            out.close();
        }
        Long endTime=System.currentTimeMillis();
        System.out.println(endTime-startTime);//640
    }

2)DataInputStream

DataInputStream的readUTF()方法能够从输入流中读取采用UTF-8编码的字符串。UTF-8编码是Unicode编码的变体。Unicode编码把所有的字符都存储为两个字节的形式。

如果实际上要存储的字节都是ASCII字符(只占7位),采用Unicode编码及其浪费存储空间。UTF-8编码能够更加有效的利用存储空间,它对ASCII字符采用一个字节形式的编码,对非ASCII字符则采用两个或两个以上字节形式的编码。

DataOutputStream的writeUTF()方法向输入流中写入采用UTF-8编码的字符串。实际上,writeUTF()方法和readUTF()方法是适合java语言的UTF变体。

 

利用DataInputStream 的一些方法不需要把要读写的数据进行字节数组来回转换(inputStream只提供了读写字节和字节数组的方法).

通常数据输出流按照一定的格式输出,在通过数据输入流按照一定的格式输入,这样可以方便的对数据进行处理。

如:通过writeUTF()把一个Unicode字符串写进去,可以使用readUTF()直接读进来。

tip:String str = "abc";等效于: char data[] = {'a', 'b', 'c'}; String str = new String(data); 

posted @ 2018-12-22 19:59  palapala  阅读(206)  评论(0编辑  收藏  举报