java---IO流

  

一.Java中流的概念细分

  1.按流的方向分(容易混淆)

     输入流: 数据流向是数据源到程序,以InputStream,Reader结尾的流

     输出流: 数据流向是程序到目的地,以OutputStream,Writer结尾的流

  2.按处理的数据单元分类

      字节流:通常以Stream结尾,以字节为单位获取数据

      字符流:通常以Reader/Writer结尾,以字符为单位获取数据

  3.按处理对象不同分类

      节点流:直接进行文件的读写,系统输入输出(System.in与System.out)都为字节流。

      包装流:通过对其他的流进行处理来提高性能

二.Java中的IO流体系

      

 三.常用的流详解

  1.文件字节流

      FileOutputStream和FileInputStream用来读取文件,适合于所有类型.

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import org.junit.Test;
/**
 * 利用文件流,实现文件的复制
 * @author MOTI
 * 
 */
public class Demo_3 {
    @Test
    public void demo3() {
        copyFile("demo1.txt", "demo3.txt");
    }
    public static void copyFile(String src,String dec) {
        FileInputStream is = null;
        FileOutputStream os = null;
        //为了提高效率,设置一个缓冲数组,读取的文件会暂时放在缓冲数组中
        byte[] bytes = new byte[1024];
        int len = 0;//每次读取的真实长度,等于-1代表读取完成
        try {
            is = new FileInputStream(src);
            os = new FileOutputStream(dec);
            try {
                //边读边写
                while((len = is.read(bytes)) != -1) {
                    //将缓冲区的数据写入到文件,注意这里写入的是真实长度,如果使用os.write(bytes)方法,那么写入的就是整个缓冲区的长度为1024
                    os.write(bytes, 0, len);
                }
                System.out.println("文件复制成功!");
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

 

  注意:

    1.为了减少对硬盘的读写次数,提高效率,通常设置缓存数组.相应的读取时使用read(byte[] b),写入的时候使用write(byte[] b,int off, int length)

    2.程序中如果出现多个流,每个流都需要单独关闭,并且关闭顺序要与创建流的顺序相反

  2.文件字符流

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.junit.Test;
/**
 *     使用FileReader和FileWriter进行文本的复制
 * @author MOTI
 */
public class Demo_4 {
    @Test
    public void demo4(){
        copyFile("demo1.txt", "demo4.txt");
    }
    public static void copyFile(String src,String dec){
        FileReader fr = null;
        FileWriter fw = null;
        int len = 0;
        //为了提高效率,缓冲区用的也是字符数组
        char[] chars = new char[1024];
        try {
            fr = new FileReader(new File(src));
            fw = new FileWriter(new File(dec));
            while((len = fr.read(chars)) != -1){
                fw.write(chars, 0, len);
            }
            System.out.println("文本复制成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(fw != null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fr != null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 

  3.缓冲字节流

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.Test;
/**
 * 使用缓冲字节流实现文件的高效复制
 * @author MOTI
 *
 */
public class Demo_5 {
    @Test
    public void demo5(){
        copyFile("demo1.txt", "demo5.txt");
    }
    public static void copyFile(String src,String dec){
        FileInputStream is = null;
        FileOutputStream os = null;
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        int len = 0;
        
        try {
            is = new FileInputStream(src);
            os = new FileOutputStream(dec);
            /*
            使用缓冲字节流包装文件字节流,增加缓冲功能,提高效率
            缓冲区的大小,默认8192,也可以自定义
             */
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(os);
            
            while((len = bis.read()) != -1){
                bos.write(len);
            }
            System.out.println("文件复制成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(bos != null){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bis != null){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(os != null){
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

  注意:关流的顺序"后开启的先关闭"

  4.缓冲字符流

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.junit.Test;
/**
 *     使用缓冲字符流,实现文本的复制
 * @author MOTI
 * BufferedReader类提供了更为方便的readline(),直接按行读取
 */
public class Demo_6 {
    @Test
    public void demo6(){
        copyFile("demo1.txt", "demo6.txt");
    }
    public static void copyFile(String src, String dec){
        FileReader fr = null;
        FileWriter fw = null;
        BufferedReader br = null;
        BufferedWriter bw = null;
        String tempString = "";
        try {
            fr = new FileReader(src);
            fw = new FileWriter(dec);
            /*
                使用缓冲字符流包装
             */
            br = new BufferedReader(fr);
            bw = new BufferedWriter(fw);
            while((tempString = br.readLine()) != null){
                //将读到的一行字符串写入文件
                bw.write(tempString);
                //下一次写入之前先换行,不然就在第一行一直追加
                bw.newLine();
            }
            System.out.println("文本复制成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fw != null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fr != null){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

  注意:

    1.readline()方法是BufferedReader特有的方法

    2.写入一行后要记得使用newLine()方法换行

  5.数据流

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.Test;

/**
 * 
 * @author MOTI
 *    DataInputStream
 *    DataOutputStream
 */
public class Demo_8 {
    @Test
    public void demo8(){
         DataInputStream dis = null;
         DataOutputStream dos = null;
         FileInputStream fis = null;
         FileOutputStream fos = null;
         try {
            fos = new FileOutputStream("demo8.txt");
            fis = new FileInputStream("demo8.txt");
            //使用数据流对缓冲流进行包装,增加缓冲功能
            dis = new DataInputStream(new BufferedInputStream(fis));
            dos = new DataOutputStream(new BufferedOutputStream(fos));
            //将下列数据写入到文件
            dos.writeInt(520);
            dos.writeUTF("哈哈哈哈,我是莫提!");
            dos.writeChar('H');
            //手动刷新缓冲区
            dos.flush();
            //直接读取数据,读取的顺序要与写入的顺序一致,不然会读取到错误数据
            System.out.println(dis.readInt());
            System.out.println(dis.readUTF());
            System.out.println(dis.readChar());
         } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if(dos != null){
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(dis != null){
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 

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

  6.对象流

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.Date;

import org.junit.Test;

/**
 *     对象流:数据源是一个对象,要求该对象的必须要进行序列化和反序列化操作
 *      对象流对象也可以对基本数据类型进行读写操作
 * @author MOTI
 *
 */
public class Dmeo_10 {
    @Test
    public void demo10() {
        write();
        read();
    }
    /**
     *     使用对象输出流将数据写入文件
     */
    public static void write() {
        //创建一个文件输出流,并包装缓冲流,增加缓冲功能
        OutputStream os = null;
        BufferedOutputStream bos = null;
        ObjectOutputStream oos = null;
        
        try {
            os  = new FileOutputStream(new File("demo10.txt"));
            bos = new BufferedOutputStream(os);
            oos = new ObjectOutputStream(bos);
            //使用Object输出流
            oos.writeInt(520);
            oos.writeDouble(2.50);
            oos.writeUTF("我是莫提!");
            //对象流对象可以对对象类型进行读写操作,但是要求必须实现序列化的接口(这里以Date对象为例)
            oos.writeObject(new Date());
            System.out.println("写入成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
    /**
     *     使用对象输入流将数据读入程序
     */
    public static void read() {
        //创建一个文件输入流,并包装缓冲流,增加缓冲功能
        InputStream is = null;
        BufferedInputStream bis = null;
        ObjectInputStream ois = null;
        
        try {
            is = new FileInputStream(new File("demo10.txt"));
            bis = new BufferedInputStream(is);
            ois = new ObjectInputStream(bis);
            //使用Object输入流按照顺序读取
            System.out.println(ois.readInt());
            System.out.println(ois.readDouble());
            System.out.println(ois.readUTF());
            System.out.println(ois.readObject().toString());
            
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

 

 

  注意:

    1.对象流不尽可以读写对象,还可以读写基本数据类型

    2.使用对象流时,该对象必须经过序列化和反序列化

    3.系统提供的类(如:Date)已经实现了序列化接口,自定义类必须手动实现

  7.转换流

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import org.junit.Test;

/**
 *     转换流:将字节流转换为字符流
 * @author  MOTI
 *
 */
public class Demo_9 {
    public static void main(String[] args) {
        //创建字符输入和输出流:使用转换流将字节流转换为字符流
        BufferedReader br = null;
        BufferedWriter bw = null;
        br = new BufferedReader(new InputStreamReader(System.in));
        bw = new BufferedWriter(new OutputStreamWriter(System.out));
        try {
            String str = br.readLine();
            while(!"exit".equals(str)){
                bw.write(str);
                bw.newLine();
                bw.flush();
                str = br.readLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally{
            if(bw != null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 

  8.随意访问文件流

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Iterator;

/**
 *     随意访问文件流:实现对一个文件的读和写,可以访问文件的任意位置
 * @author MOTI
 *
 */
public class Demo_11 {
    public static void main(String[] args) {
        RandomAccessFile raf = null;
        int[] data = {10,20,30,40,50,60,70,80,90,100};
        try {
            raf = new RandomAccessFile("demo11.txt", "rw");
            for (int i : data) {
                raf.writeInt(i);
            }
            //直接读取文件,位置从第36个字节开始
            raf.seek(4);
            System.out.println(raf.readInt());//读取4个字节(int为4个字节)
            //直接读取数据,隔一个读取一个
            for (int i = 0; i < data.length; i += 2) {
                raf.seek(i * 4);
                System.out.print(raf.readInt()+"\t");
            }
            System.out.println();
            //在第8字节处,插入新数据,替换原来的30
            raf.seek(8);
            raf.writeInt(520);
            //遍历查看结果
            for (int i = 0; i < data.length; i ++) {
                raf.seek(i * 4);
                System.out.print(raf.readInt()+"\t");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  注意学习这个流需要掌握三个核心方法:

    1.RandomAccessFile(String name, String mode);

          name 用于确定文件,mode去r(读),或rw(读写),以此来确定对流的访问权限

    2.seek(long a);

          用来定位流对象读写文件的位置,a确定读写位置距离文件开头的字节数.

    3.getFilePointer();

          用来获得流当前的读写位置

四.Java对象的序列化和反序列化

 1.序列化和反序列化的概念

  把对象转换为字节序列的过程称为对象的序列化
  把字节序列恢复为对象的过程称为对象的反序列化
  对象的序列化主要有两种用途:
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

  在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

  当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

  2.JDK类库中的序列化API

  java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
  java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
  只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
  对象序列化包括如下步骤:
  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
  2) 通过对象输出流的writeObject()方法写对象。

  对象反序列化的步骤如下:
  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
  2) 通过对象输入流的readObject()方法读取对象

  准备一个Student类,并让该类实现Serializable接口

import java.io.Serializable;

public class Student implements Serializable {
    // 添加序列化ID,他决定了是否能够反序列化成功
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;
    boolean isMan;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public boolean isMan() {
        return isMan;
    }

    public void setMan(boolean isMan) {
        this.isMan = isMan;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", isMan=" + isMan + "]";
    }

    public Student() {
        super();
        // TODO Auto-generated constructor stub
    }

    public Student(String name, int age, boolean isMan) {
        super();
        this.name = name;
        this.age = age;
        this.isMan = isMan;
    }

}

 

开始将Student类的对象序列化和反序列化 

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * java 对象的序列化和反序列化
 * @author MOTI
 *
 */
public class SerializableTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        ObjectInputStream ois = null;
        ObjectOutputStream oos = null;
        
        Student student = new Student("莫提", 20, true);
        Student student1 = new Student("Moti", 20, true);
        //通过ObjectOutputStream将Student对象写到文件中,即为序列化
        try {
            fos = new FileOutputStream("serializabletest.txt");
            oos = new ObjectOutputStream(fos);
            oos.writeObject(student);
            oos.writeObject(student1);
            System.out.println("序列化成功!");
            //**************************************************
        //通过ObjectInputStream将文件中的数据变回原来的对象
            fis = new FileInputStream("serializabletest.txt");
            ois = new ObjectInputStream(fis);
            Student s = (Student) ois.readObject();
            Student s1 = (Student) ois.readObject();
            System.out.println(s);
            System.out.println(s1);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(oos != null) {
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(ois != null) {
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

 

转载于:https://www.cnblogs.com/cnmoti/p/10720518.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值