IO流技术

IO流技术介绍

输入(input)指的是:可以让程序从外部系统获得数据(核心含义是“读”,读取外部数据)。

输出(output)指的是:程序输出数据给外部系统从而可以操作外部系统(核心含义是“写”,将数据写出到外部系统)。

数据源(data source):提供数据的原始媒介。常见的数据源有:数据库、文件、其他程序、内存、网络连接、IO设备。

数据源分为:源设备、目标设备

源设备:为程序提供数据,一般对应输入流。

目标设备:程序数据的目的地,一般对应输出流。

流:是一个抽象、动态的概念,是一连串连续动态的数据集合。

对于输入流而言。通过流(A stream)将数据源(Source)中的数据(information)输送到程序(Program)中。

对于输出流而言,目标数据源就是目的地(dest),通过流将程序中的数据送到目标数据源中。

输入/输出流的划分是相对程序而言的,并不是相对数据源。

一个简单的IO流程序

当程序需要读取数据源的数据时,就会通过IO流对象开启一个通向数据源的流,通过这个IO流的对象的相关方法可以顺序的读取数据源中的数据。

在d盘创建一个名为a.txt的文本文件,内容写abc

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Test01 {
    public static void main(String[] args) {
        try {
            //创建一个流对象
            FileInputStream fis = new FileInputStream("d:/a.txt");
            int s1 = fis.read();
            int s2 = fis.read();
            int s3 = fis.read();
            int s4 = fis.read();//由于文件已经读完,所以返回-1
            System.out.println(s1);  //打印输出字符的ASCII码值
            System.out.println(s2);
            System.out.println(s3);
            System.out.println(s4);
            //流对象使用完毕,必须关闭,不然,总占用系统资源,最总会造成系统崩溃
            fis.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

97
98
99
-1 

 以上案例需要注意:

        我们读取的文件内容是已知的,因此可以使用固定次数的int s = fis.read();"语句读取内容,但是在实际开发中通常我们根本不知道文件的内容,因此我们在读取的时候需要配合while循环使用。
        为了保证出现异常后流的正常关闭,通常要将流的关闭语句要放到finally语句块中,并且要判断流是不是null。

IO流经典写法

import java.io.FileInputStream;
import java.io.IOException;

public class Test2 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try{
            fis = new FileInputStream("d:/a.txt");
            StringBuilder sb  = new StringBuilder();
            int temp = 0;
            while((temp = fis.read()) != -1){
                sb.append((char) temp);
            }
            System.out.println(sb);
        }catch(Exception e){
            e.printStackTrace();
        }finally{
                try {
                    if(fis != null){
                    fis.close();
                  }
                } catch (IOException e) {
                    e.printStackTrace();
            }
        }
    }
}

abc 

IO流新语法经典写法

在JDK7以及以后的版本中可以使用try-with-resource 语法更优雅的关闭资源。
java.lang.AutoCloseable接口:
在java.lang.Autocloseable接口中包含了一个close方法,该方法用于关闭资源。只要是实现了java.lang.AutoCloseable接口的对象,都可以使用try-with-resource关闭资源。

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class Test3 {
    public static void main(String[] args) {

        try(FileInputStream fis = new FileInputStream("d:/a.txt");){
            StringBuilder sb = new StringBuilder();
            int temp = 0;
            while ((temp = fis.read()) != -1){
                sb.append((char)temp);
            }
            System.out.println(sb);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

abc 

FileInputStream的父类的父类实现了AutoCloseable接口,所以可以使用try-with-resource简化。

如上一段代码是一段经典的IO流代码,其他对象的使用也基本是同样的模式。

Java中流的概念细分

按流的方向分类:
输入流:数据流向是数据源到程序(以InputStream、Reader结尾的流)。
输出流:数据流向是程序到目的地 (以OutPutstream、Writer结尾的流)。

按处理的数据单元分类:
字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,如FileInputStream、
FileOutputStream。
字符流:以字符为单位获取数据,命名上以Reader/Writer结尾的流一般是字符流,如
FileReader、FileWriter。


按处理对象不同分类:
节点流:可以直接从数据源或目的地读写数据,如FileInputstream、FileReader等。
处理流:不直接连接到数据源或目的地,是”处理流的流’通过对其他流的处理提高程序的性能,如BufferedIinputstream、BufferedReader等。处理流也叫包装流。(比如FileReader每次只能读取一个字符,而再加上一个处理流BufferedReader之后就可以一次读取一行的字符)

节点流处于IO操作的第一线,所有操作必须通过它们进行;处理流可以对节点流进行包装,提高性能或提高程序的灵活性。

 

 IO流体系

注:这里只列出常用的类,详情可以参考JDK API文档。
从上图发现,很多流都是成对出现的,比如:FilelnputStream/Fileoutputstream,显然是对文件做输入和输出操作的。我们下面简单做个总结:
1.InputStream/OutputStream
字节流的抽象类。
2. Reader/Writer
字符流的抽象类。
3. FileInputStream/FileOutputStream
节点流:以字节为单位直接操作”文件”

4.ByteArrayInputStream/ByteArrayOutputStream
节点流:以字节为单位直接操作"字节数组对象”。
5.ObjectInputStream/ObjectOutputStream
 处理流:以字节为单位直接操作”对象”。
6.DataInputStream/DataOutputStream
处理流:以字节为单位直接操作"基本数据类型与字符串类型”。
7.FileReader/FileWriter
节点流:以字符为单位直接操作"文本文件,(注意:只能读写文本文件)。
8.BufferedReader/BufferedWriter
处理流:将ReaderWriter对象进行包装,增加缓存功能,提高读写效率。
9.BufferedInputStream/BufferedOutputStream
处理流:将InputStream/Outputstream对象进行包装,增加缓存功能,提高读写效率
10.InputStreamReader/OutputStreamWriter
处理流:将字节流对象转化成字符流对象。
 11.PrintStream
处理流:将OutputStream进行包装,可以方便地输出字符,更加灵活。

上面的解释,一句话就点中了流的核心作用。大家在后面学习的时候,用心体会。

IO流的四大抽象类 

InputStream/OutputStream和Reader/Writer类是所有IO流类的抽象父类,我们有必要简单了解一下这个四个抽象类的作用。然后,通过它们具体的子类熟悉相关的用法。


InputStream

此抽象类是表示字节输入流的所有类的父类。InputSteam是一个抽象类,它不可以实例化。数据的读取需要由它的子类来实现。根据节点的不同,它派生了不同的节点流子类。

继承自InputSteam的流都是用于向程序中输入数据,旦数据的单位为字节 (8 bit)。

方法使用说明
int read()读取一个字节的数据,并将字节的值作为int类型返回(0-255之间的一个值)。如果未读出字节,则返回-1(返回值为-1表示读取结束)

void close()

关闭输入流对象,释放相关系统资源

 OutputStream

此抽象类是表示字节输出流的所有类的父类。输出流接收输出字节,并将这些字节发送到某个目的地。

方法说明
void write(int n)向目的地中写入一个字节
void close()关闭输出流对象,释放相关系统资源

Reader 

Reader用于读取的字符流抽象类,数据单位为字符。

方法说明
int read()读取一个字符的数据,并将字符的值作为int类型返回(0-65535之间的一个值,即Unicode值)。如果未读出字符则返回-1(返回-1表示读取结束)
void close()关闭流对象,释放相关系统资源

 Writer

Writer用于输出的字符流抽象类,数据单位为字符。

方法说明
void writer(int n)向输出流中写一个字符
void close()关闭输出流对象,释放相关系统资源

文件字节流 

FileInputStream通过字节的方式读取文件,适合读取所有类型的文件(图像、视频、文本文件等)。
FileOutputStream 通过字节的方式写数据到文件中,适合所有类型的文件(图像、视频、文本文件等)。

FileInputStream文件输入字节流

import java.io.FileInputStream;
import java.io.IOException;

public class TestFileInputStream {
    public static void main(String[] args) {
//使用try-with-resource方式关闭资源。
//在try中打开资源,不需要在代码中添加finally块关闭资源。
        try(FileInputStream fis = new FileInputStream("d:/a.txt")){
            StringBuilder sb = new StringBuilder();
            int temp = 0;
            while((temp = fis.read()) != -1){
                sb.append((char)temp);
            }
            System.out.println(sb);
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}

FileOutputStream文件输出字节流

import java.io.FileOutputStream;
import java.io.IOException;

public class TestFileOutputStream {
    public static void main(String[] args) {
        //true:表示内容会追加到文件的末尾,false表示重写整个文件中的内容,什么都不写默认为false
        try(FileOutputStream fos = new FileOutputStream("d:/a.txt",true)){
                //准备输出的数据
            String str = "Old Lu";
            fos.write(str.getBytes());
            //刷新将数据从内存中写入到磁盘中
            fos.flush();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

字节缓冲区 

未加字节缓冲区,运行时间远远大于加了字节缓冲区的代码

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TestFileByteBuffer {
    public static void main(String[] args) {
        long time1 = System.currentTimeMillis();
        copyFile("d:/1.jpg","d:/2.jpg");
        long time2 = System.currentTimeMillis();
        System.out.println(time2 - time1);
    }

    /**
     *
     * @param source 源文件
     * @param destination 目的地文件
     */
    public static void copyFile(String source,String destination ){
            //“后开先关”,try-with-resource按照IO流对象被创建的顺序的逆序来关闭
            try(FileInputStream fis = new FileInputStream(source);
                FileOutputStream fos = new FileOutputStream(destination)){

                int temp = 0;
                while((temp = fis.read()) != -1){
                    fos.write(temp);
                }
                //将数据从内存中写出到磁盘中
                fos.flush();
            }catch(IOException e){
                e.printStackTrace();
            }
    }
}

加了字节缓冲区

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TestFileByteBuffer {
    public static void main(String[] args) {
        long time1 = System.currentTimeMillis();
        copyFile("d:/1.jpg","d:/2.jpg");
        long time2 = System.currentTimeMillis();
        System.out.println(time2 - time1);
    }

    /**
     *
     * @param source 源文件
     * @param destination 目的地文件
     */
    public static void copyFile(String source,String destination ){
            //“后开先关”,try-with-resource按照IO流对象被创建的顺序的逆序来关闭,先关闭下面destination后关闭source
            try(FileInputStream fis = new FileInputStream(source);
                FileOutputStream fos = new FileOutputStream(destination)){

                //创建字节缓冲区
                byte[] buffer = new byte[1024];

                int temp = 0;
                while((temp = fis.read(buffer)) != -1){ //一次读一个buffer数组大小(1024)的内容
                    fos.write(buffer,0,temp); //0:写入的位置在buffer数组中索引为0,temp:结束索引的位置为temp,数组的长度等于temp
                }
                //将数据从内存中写出到磁盘中
                fos.flush();
            }catch(IOException e){
                e.printStackTrace();
            }
    }
}

 缓冲字节流

        Java缓冲流本身并不具有IO流的读取与写入功能,只是在别的流(节点流或其他处理流) 上加上缓冲功能提高效率,就像是把别的流包装起来一样,因此缓冲流是一种处理流(包装流)。
BufferedInputStream和BufferedOutputStream这两个流是缓冲宇节流,通过内部缓存数组来提高操作流的效率。


使用缓冲流实现文件的高效率复制
下面我们通过两种方式(普通文件字节流与缓冲文件字节流)实现一个文件的复制,来体会一下缓冲流的好处。

import java.io.*;

public class TestFileBufferStream {
    public static void main(String[] args) {
        long time1 = System.currentTimeMillis();
        copyFile("d:/1.jpg","d:/2.jpg");
        long time2 = System.currentTimeMillis();
        System.out.println(time2 - time1);
    }

    /**
     *
     * @param source 源文件
     * @param destination  目的地文件
     */
    public static void copyFile(String source,String destination){
            //实例化节点流对象
        try(FileInputStream fis = new FileInputStream(source);
            FileOutputStream fos = new FileOutputStream(destination);
            //实例化处理流对象
            BufferedInputStream bis = new BufferedInputStream(fis);
            BufferedOutputStream bos = new BufferedOutputStream(fos)){

            int temp = 0;
            while((temp = bis.read()) != -1){
                bos.write(temp);
            }

            bos.flush();   //强制输出数据,清空缓冲区

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

    }
}

 注意:

在关闭流时,应 最先关闭最外层的包装流,即“后开的先关闭”。

缓冲区的大小默认是8192字节,也可以使用其他的构造方法自己指定大小,如:BufferedOutputStream(inputStream in)的另一个构造方法BufferedOutputStream(inputStream in,int size)。

文件字符流

前面介绍文件字节流可以处理所有文件,如果我们处理的是文本文件也可以使用文件字符流,它以字符为单位进行操作。

文件字符输入流

import java.io.FileReader;
import java.io.IOException;

public class TestFileReader {
    public static void main(String[] args) {
        //创建文件字符输入流对象
        try(FileReader fr  = new FileReader("d:/a.txt")){

            StringBuilder sb = new StringBuilder();

            //操作流对象
            int temp = 0;
            while((temp = fr.read()) != -1){
                sb.append((char) temp);  //强制类型转换
            }
            System.out.println(sb);
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

abc 

文件字符输出流

import java.io.FileWriter;
import java.io.IOException;

public class TestFileWriter {
    public static void main(String[] args) {
        //创建文件字符输出流对象
        //true:表示开启追加,false:表示覆盖文件中的内容。默认为false
        try(FileWriter fw = new FileWriter("d:/aa.txt",true)){
        //输入内容,其中\r\n表示回车加换行,如果不加这两个转义字符,就默认追加在原本内容后面       
        fw.write("您好\r\n"); 
        fw.write("您好Old\r\n");
        fw.write("您好IT\r\n");
        fw.flush();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

您好

您好Old

您好IT 

缓冲字符流

BufferedReader/BufferedWriter增加了缓存机制,大大提高了读写文本文件的效率。

字符输入缓冲流

BufferedReader是针对字符输入流的缓冲流对象,提供了更方便的按行读取的方法:readLine();在使用字符流读取文本文件时,我们可以使用该方法以行为单位进行读取。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TestBufferedReader {
    public static void main(String[] args) {
        //创建字符输入缓冲流以及文件字符流对象
        try(BufferedReader br = new BufferedReader(new FileReader("d:/aa.txt"))){

            //操作字符输入缓冲流
           String temp = "";
           while((temp = br.readLine()) != null){
               System.out.println(temp);
           }

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

字符输出缓冲流

BufferedWriter是针对字符输出流的缓冲流对象,在宇符输出缓冲流中可以使用newLine();方法实现换行处理。

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class TestBufferedWriter {
    public static void main(String[] args) {
        //创建字符输出缓冲流以及文件字符输出流对象
        try(BufferedWriter bw = new BufferedWriter(new FileWriter("d:/sxt.txt"))){
        //操作字符输出缓冲流
            bw.write("您好");
            bw.write("您好lu");
            //换行
            bw.newLine();
            bw.write("何以解忧");
            bw.newLine();
            bw.write("唯有杜康");
            bw.flush();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

注意
readLine()方法是BufferedReader的方法,可以对文本文件进行更加方便的读取操作。
newLine()方法BufferedWriter的方法,可以使用newLine()方法换行。

import java.io.*;

public class TestLineNumber {
    public static void main(String[] args) {
        //创建字符输入缓冲流与文件字符输入流对象
        try(BufferedReader br = new BufferedReader(new FileReader("d:/sxt.txt"));
            //创建字符输出缓冲流与文件字符输出流对象
            BufferedWriter bw = new BufferedWriter(new FileWriter("d:/sxt2.txt"))){

            //定义行号的变量
            int i = 1;
            String temp = "";
            while((temp = br.readLine()) != null){
                //将读取到的一行内容添加行号,并写出到目标文件中。
                bw.write(i+","+temp);
                //换行处理
                bw.newLine();
                //行号变量累加
                i++;
            }
            //刷新
            bw.flush();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

转换流

InputStreamReader/OutStreamWriter用来实现将字节流转化成字符流。

InputStreamReader提供字节流到字符流之间的转换

OutputStreamWriter提供字符流到字节流之间的转换

输入一个UTF-8格式的文本文档,因为InputStreamReader isr = new InputStreamReader(fis)默认是UTF-8格式,所以不会出现乱码。

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class TestInputStreamReader {
    public static void main(String[] args) {
        //创建文件字节输入流对象
        try(FileInputStream fis = new FileInputStream("d:/sxt3.txt");
            //字节到字符的转换流
            InputStreamReader isr = new InputStreamReader(fis)){
            StringBuilder sb = new StringBuilder();

            //操作流
            int temp = 0;
            while((temp = isr.read()) != -1){
                sb.append((char)temp);
            }
            System.out.println(sb);

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

    }
}

输入一个ANIS格式的文本文档,必须加上转换格式为“gbk”,否者汉字部分将出现乱码InputStreamReader isr = new InputStreamReader(fis,"gbk")

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class TestInputStreamReader {
    public static void main(String[] args) {
        //创建文件字节输入流对象
        try(FileInputStream fis = new FileInputStream("d:/sxt3.txt");
            //字节到字符的转换流
            InputStreamReader isr = new InputStreamReader(fis,"gbk")){
            StringBuilder sb = new StringBuilder();

            //操作流
            int temp = 0;
            while((temp = isr.read()) != -1){
                sb.append((char)temp);
            }
            System.out.println(sb);

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

    }
}

通过字节流读取文本文件并添加行号

import java.io.*;

public class TestLineNumber2 {
    public static void main(String[] args) {
        //创建字符输入缓冲流、输入字节到字符的转换流、文件字节输入流对象
        try(BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("d:/sxt.txt")));
        //创建字符输出缓冲流、输出字符到字节的转换流、文件的字节输出流对象
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("d:/sxt4.txt")))){

            //操作流
            String temp = "";
            int i = 1;
            while((temp = br.readLine()) != null){
                //将添加行号的内容输出到目标文件中
                bw.write(i+","+temp);
                //换行
                bw.newLine();
                //序号累加
                i++;
            }
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

 通过转换流实现键盘输入屏幕输出

System.in是字节流对象,代表键盘的输入

System.out是字节流对象,代表输出到屏幕

import java.io.*;

public class TestKeyboardInput {
    public static void main(String[] args) {
        //创建键盘输入相关流对象
        try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //创建向屏幕输出相关流对象
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out))){

           while (true){
               bw.write("请输入:");
               bw.flush();
               //获取键盘输入的字符串
               String input = br.readLine();
               //判断输入的内容是否含有退出关键
//建议使用"字符串".equals(input)而不是input.equal("字符串"),因为当输入为空时,会报空指针异常
               if("exit".equals(input) || "quit".equals(input)){
                   bw.write("Bye Bye !");
                   bw.flush();
                   break;
               }
               bw.write("您输入的是:"+input);
               bw.newLine();
               bw.flush();
           }
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

字符输出流

在Java的IO流中专门提供了用于字符输出的流对象PrintWriter。该对象具有自动行刷新缓冲字符输出流,特点是可以按行写出字符串,并且可通过println();方法实现自动换行。

import java.io.IOException;
import java.io.PrintWriter;

public class TestPrintWriter {
    public static void main(String[] args) {
        //创建字符输出流对象
        try(PrintWriter pw = new PrintWriter("d:/sxt5.txt")){
            //调用不带有换行方法完成内容输出
            pw.print("abc");
            pw.print("def");
            //调用带有自动换行方法完成内容输出
            pw.println("oldlu");
            pw.println("sxt");
            pw.flush();

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

通过字符输出流添加行号

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;

public class TestLineNumber3 {
    public static void main(String[] args) {
        //创建字符输入缓冲流与文件字符输入流
        try(BufferedReader br = new BufferedReader(new FileReader("d:/sxt.txt"));
        //创建字符输出流
            PrintWriter pw = new PrintWriter("d:/sxt6.txt")){

            //操作流
            String temp ="";
            //定义序号变量
            int i=1;
            while((temp = br.readLine()) != null){
                //输出内容并带有换行效果
                pw.println(i+","+temp);
                //序号累加
                i++;
            }
            //刷新
             pw.flush();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

数据流

数据流将“基本数据类型与字符串类型”作为数据源,从而允许程序以与机器无关的方式从底层输入输出流中操作Java基本数据类型与字符串类型。

DataInputStream和DataOutputStream提供可以存取与机器无关的所有Java基础类型数据(如:int、double、String等)的方法。


import java.io.*;

public class TestDataStream {
    public static void main(String[] args) {
        //创建数据输出流对象与文件字节输出流对象
        try(DataOutputStream dos = new DataOutputStream(new FileOutputStream("d:/data"));
        //创建数据输入流对象与文件字节输入流对象
            DataInputStream dis = new DataInputStream(new FileInputStream("d:/data"))){

            //将如下数据写入到文件中
            dos.writeChar('a');
            dos.writeInt(10);
            dos.writeDouble(Math.random());
            dos.writeBoolean(true);
            dos.writeUTF("北京欢迎你");
            dos.flush();

            //直接读取数据:读取的顺序需要与上面写入顺序一致。否则不能正确读取数据。
            System.out.println("char: "+dis.readChar());
            System.out.println("int: "+dis.readInt());
            System.out.println("Double: "+dis.readDouble());
            System.out.println("Boolean: "+dis.readBoolean());
            System.out.println("String: "+dis.readUTF());
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

提示:使用数据流时,读取的顺序一定要与写入的顺序一致,否则不能正确读取数据。

对象流

前面的数据流只能实现对基本数据类型和字符串类型的读写,并不能读取对象(字符串除外),如果要对某个对象进行读写操作,我们需要学习一对新的处理流:

ObjectInputStream/ObjectOutputStream。

import java.io.*;

public class TestObjectStreamBasicType {
    public static void main(String[] args) {
        //创建对象输出字节流,文件字节输出流对象
        try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/data2"));
        //创建对象输入字节流,文件字节输入流对象
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/data2"))){

            //将数据输出到数据文件中
            oos.writeInt(10);
            oos.writeDouble(Math.random());
            oos.writeChar('a');
            oos.writeBoolean(true);
            oos.writeUTF("您好,lu");
            //刷新
            oos.flush();

            //必须按照写入的顺序读取数据
            System.out.println("Int: "+ois.readInt());
            System.out.println("Double: "+ois.readDouble());
            System.out.println("Char: "+ois.readChar());
            System.out.println("Boolean: "+ois.readBoolean());
            System.out.println("String: "+ois.readUTF());


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

注意:

对象流不仅可以读写对象,还可以读写基本数据类型,读写基本数据类型时,读取的顺序一定要与写入的顺序一致,否则不能正确读取数据。

ObjectInputStream/ObjectOutputStream需要的节点流类型是字节流类型

将对象序列化到文件

序列化和反序列化是什么?
        当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。比如,我们可以通过http协议发送字符串信息;我们也可以在网络上直接发送Java对象。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象才能正常读取。
把Java对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为Java对象的过程称为对象的反序列化。


序列化涉及的类和接口
        ObjectOutputStream代表对象输出流,它的writeObject(Object  obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

        ObjectInputStream代表对象输入流,已的readObject()方法从一个源输入流中读取宇节序列,再把它们反序列化为一个对象,并将其返回。
        只有实现了Serializable接口的类的对象才能被序列化。Serializable接口是一个空接口,只起到标记作用。

 将对象序列化到文件

ObjectOutputStream可以将一个内存中的Java对象通过序列化的方式写入到磁盘的文件中。被序列化的对象心须要实现Serializable序列化接口,否则会抛出异常。

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class TestObjectOutputStream {
    public static void main(String[] args) {
        //创建对象输出字节流与文件字节输出流对象
        try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("d:/data3"))){
        //创建Users对象
            Users users = new Users();
            users.setUserage("20");
            users.setUsername("OldLu");
            users.setUserid(1);

            //将Users对象序列化到文件中
            oos.writeObject(users);
            //刷新
            oos.flush();

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

import java.io.Serializable;

public class Users implements Serializable {
    private int userid;
    private String username;
    private String userage;

    public int getUserid() {
        return userid;
    }

    public void setUserid(int userid) {
        this.userid = userid;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUserage() {
        return userage;
    }

    public void setUserage(String userage) {
        this.userage = userage;
    }

    @Override
    public String toString() {
        return "Users{" +
                "userid=" + userid +
                ", username='" + username + '\'' +
                ", userage='" + userage + '\'' +
                '}';
    }
}

将对象反序列化到内存

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class TestObjectInputStream {
    public static void main(String[] args) {
        //创建对象字节输入流与文件字节输入流对象
        try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/data3"))){
            //反序列化处理
            Users users = (Users) ois.readObject();
            System.out.println(users);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

File类在IO中的作用

        当以文件作为数据源或目标时,除了可以使用字符串作为文件以及位置的指定以外,我们也可以使用File类指定。

import java.io.*;

public class TestFile {
    public static void main(String[] args) {
        //创建字符缓冲流与文件字符输入流对象
        try(BufferedReader br = new BufferedReader(new FileReader(new File("d:/sxt.txt")));
        //创建字符输出流对象
            PrintWriter pw = new PrintWriter(new File("d:/sxt9.txt"))){

            //操作流
            String temp = "";
            int i=1;
            while((temp = br.readLine()) != null){
                pw.println(i+","+temp);
                i++;
            }
            pw.flush();
        }catch(IOException e){
            e.printStackTrace();
        }
    }
}

装饰器模式构建IO体系

        装饰器模式是GOF23种设计模式中较为常见的一种模式。它可以实现对原有类的包装和装饰,使新的类具有更强的功能。

装饰器模式

class Iphone{
    private String name;
    public Iphone(String name){
        this.name = name;
    }
    public void show(){
        System.out.println("我是"+name+", 可以在屏幕上显示");
    }
}

class TouyingPhone{
    public Iphone iphone;
    public TouyingPhone(Iphone iphone){
        this.iphone = iphone;
    }
    public void show(){
        iphone.show();
        System.out.println("还可以投影,在墙壁上显示");
    }
}


public class TestDecoration {
    public static void main(String[] args) {
        Iphone iphone = new Iphone("Iphone30");
        iphone.show();
        System.out.println("===================将具有投影能力的手机壳装在手机上");
        TouyingPhone tp = new TouyingPhone(iphone);
        tp.show();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值