GVKun编程网logo

java---IO流(javaio流分为几种)

20

本篇文章给大家谈谈java---IO流,以及javaio流分为几种的知识点,同时本文还将给你拓展Java&IO流、JavaIO流、javaIO流(二)IO流概述、Java|IO流等相关知识,希望对各位

本篇文章给大家谈谈java---IO流,以及javaio流分为几种的知识点,同时本文还将给你拓展Java & IO流、Java IO流、java IO流 (二) IO流概述、Java | IO流等相关知识,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

java---IO流(javaio流分为几种)

java---IO流(javaio流分为几种)

  

一.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();
                }
            }
        }
    }
}

 

Java & IO流

Java & IO流

转换流:
InputStreamReader :字节到字符的桥梁。解码。
OutputStreamWriter:字符到字节的桥梁。编码。
 
流的操作规律:
之所以要弄清楚这个规律,是因为流对象太多,开发时不知道用哪个对象合适。
 
想要知道开发时用到哪些对象。只要通过四个明确即可。
 
1,明确源和目的(汇)
源:InputStream  Reader
目的:OutputStream  Writer
 
2,明确数据是否是纯文本数据。
源:是纯文本:Reader
否:InputStream
目的:是纯文本 Writer
否:OutputStream
 
到这里,就可以明确需求中具体要使用哪个体系。
 
3,明确具体的设备。
源设备:
硬盘:File
键盘:System.in
内存:数组
网络:Socket流
 
目的设备:
硬盘:File
控制台:System.out
内存:数组
网络:Socket流
 
4,是否需要其他额外功能。
1,是否需要高效(缓冲区);
是,就加上buffer.
2,转换。
 
 
 
需求1:复制一个文本文件。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream  Writer
2,是否是纯文本?
是!
源:Reader
目的:Writer
 
3,明确具体设备。
源:
硬盘:File
目的:
硬盘:File
 
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
 
4,需要额外功能吗?
需要,需要高效。
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
 
================================================
 
需求2:读取键盘录入信息,并写入到一个文件中。
 
1,明确源和目的。
源:InputStream Reader
目的:OutputStream  Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确设备
源:
键盘。System.in
目的:
硬盘。File
 
InputStream in = System.in;
FileWriter fw = new FileWriter("b.txt");
这样做可以完成,但是麻烦。将读取的字节数据转成字符串。再由字符流操作。
4,需要额外功能吗?
需要。转换。 将字节流转成字符流。因为名确的源是Reader,这样操作文本数据做便捷。
所以要将已有的字节流转成字符流。使用字节-->字符 。InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("b.txt");
 
还需要功能吗?
需要:想高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
 
 
 
===================================================
 
需求3:将一个文本文件数据显示在控制台上。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream  Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确具体设备
源:
硬盘:File
目的:
控制台:System.out
 
FileReader fr = new FileReader("a.txt");
OutputStream out = System.out;//PrintStream
4,需要额外功能吗?
需要,转换。
FileReader fr= new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(System.out);
需要,高效。 
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
 
================================================================
 
需求4:读取键盘录入数据,显示在控制台上。
1,明确源和目的。
源:InputStream Reader
目的:OutputStream  Writer
2,是否是纯文本呢?
是,
源:Reader
目的:Writer
3,明确设备。
源:
键盘:System.in
目的:
控制台:System.out
 
InputStream in = System.in;
OutputStream out = System.out;
 
4,明确额外功能?
需要转换,因为都是字节流,但是操作的却是文本数据。
所以使用字符流操作起来更为便捷。
InputStreamReader isr = new InputStreamReader(System.in);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
 
为了将其高效。
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
 
 
============================================================
 
5,将一个中文字符串数据按照指定的编码表写入到一个文本文件中.
 
1,目的。OutputStream,Writer
2,是纯文本,Writer。
3,设备:硬盘File 
FileWriter fw = new FileWriter("a.txt");
fw.write("你好"); 
 
注意:既然需求中已经明确了指定编码表的动作。
那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表。
只能使用其父类。OutputStreamWriter.
OutputStreamWriter接收一个字节输出流对象,既然是操作文件,那么该对象应该是FileOutputStream
 
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName);
 
需要高效吗?
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName));
 
什么时候使用转换流呢?
 
1,源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁。
提高对文本操作的便捷。
2,一旦操作文本涉及到具体的指定编码表时,必须使用转换流 。

Java IO流

Java IO流

1、站在内存的角度看待方向,从其他设备进入内存的,都是输入,从内存到其他设备的,都是输出

  I/O就是用于设备之间进行数据交互的对象所属的类型

2、java中操作设备设备之间数据传输的对象,都是IO流对象,这些对象所属的类型,都在io包中

3、按照流向分为输入流和输出流

  输入流:其它设备到内存的流对象   进行读取

  输出流:内存流到其它设备的流对象   进行写出

4、按照功能分为字节流和字符流

  字节流:直接操作字节的流对象

  字符流:直接操作字符的流对象  字符流 = 字节流+编码格式

5、字节流:

  输入(读取):InputStream  使用子类操作 FileInputStream(File file)   FileInputStream(String path)

    read()一个个字节读取   read(byte[] b)一个个读取字节到数组,返回数组

  输出(写入):OutputStream  使用子类操作 FileOutputStream(File file)  FileInputStream(String path) 

     writer()一个个字节写入  writer(byte[] b)

6、字符流:使用字节流可以操作字符,但字符长度不一致时会产生乱码。注:字符流无法操作非纯文本文件

  输入(读取):Reader    使用子类操作 FileReader(File file)  FileReader(String path)

    方法同字节流,用来处理不是一个字符长度的的字符文件  高效缓冲流多一个readLine()一次读取一行

  输出(写入):Writer     使用子类操作 FileWriter(File file)  FileWriter(String path)

    方法同字节流,但高效缓冲流有特有方法newLine() 用来写换行符,解决各个系统换行符不同问题

 

import java.io.FileInputStream;

public class test1 {

    public static void main(String[] args) throws Exception {
        FileInputStream fis = new FileInputStream("test.txt");
        int i=0;
        byte[] b = new byte[2];
        while((i=fis.read(b))!=-1) {
            System.out.println(new String(b,0,i));
        }        
    }
}
字节流读纯汉字文本

 

7、在使用流操作之前,应进行导包,io包,在操作时应解决异常,操作完毕后应关闭资源

8、高效缓冲流 BufferedInputStream和BufferedOutputStream

  1、采用装修设计模式,对某个类的功能进行增强(且不用继承该类,将该类的一个对象传入该类)

  2、原理:该类型提供了一个8192字节的数组,当外界调用read()方法时,一次性的读取8192个字节到数组中,对象再次调用时就不需要访问磁盘。写入时也直接写进数组,等8192字节写满后,一次性写入,不需要一直写入磁盘,如果没有写满,在关闭流对象时也会写入磁盘。

public class Test2 {

    public static void main(String[] args) {
        // 装修设计模式
        Man m = new Man();
        SuperMan superman = new SuperMan(m);
        superman.fly();

    }

}
class Man{
    public void run() {
        System.out.println("i can run");
    }
}
class SuperMan{
    Man man = null;
    public SuperMan(Man man) {
        this.man = man;
    }
    public void run() {
        man.run();
        System.out.println("i can fly");
    }
}
装修设计模式

9、close()和flush()

  close()方法使用时会先调用flush()方法

  流对象一旦使用close()关闭,则无法继续使用

  flush()只是将缓冲区的数据刷新到相应的文件,不会关闭流对象,字节流会自动刷新,字符流则需要手动刷新

10、练习

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

public class MoniRead {

    public static void main(String[] args) throws Exception {
        // TODO Auto-generated method stub
        MyInputStream m = new MyInputStream("aa.txt");
        byte[] b = new byte[2];
        int len=0;
        while((len=m.myRead(b))!=-1) {
            System.out.println(new String(b,0,len));
        }
        
    }

}
class MyInputStream{
    
    private File f;
    private FileInputStream f1;
    public MyInputStream(String s) throws FileNotFoundException {
        f = new File(s);
        if(!f.exists()) {
            FileNotFoundException e = new FileNotFoundException();
            throw e;
        }
        f1 = new FileInputStream(f);
    }
    public MyInputStream(File f) throws FileNotFoundException {
        if(!f.exists()) {
            FileNotFoundException e = new FileNotFoundException();
            throw e;
        }
        f1 = new FileInputStream(f);
    }
    //    read(byte[] b)   int 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
    public int myRead(byte[] b) throws IOException {    
        int i=0;
        int len=0;
        while(len<b.length&&(i=f1.read())!=-1) {
            b[len]=(byte)i;
            len++;
        }
        return len;
    }

    //    read()  从输入流中读取数据的下一个字节。 int
    public int myRead() throws IOException {
        return f1.read();
    }
}
模拟read()
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class MoniReader {

    public static void main(String[] args) throws Exception {
        File f = new File("aa.txt");
        FileReader fr = new FileReader(f);
        MyBufferedReader mbr = new MyBufferedReader(fr);
        String line=null;
        while((line = mbr.myReadLine())!=null) {
            System.out.println(line);
        }
    }

}
class MyBufferedReader{
    private BufferedReader br ;

    public MyBufferedReader(FileReader f){
        br = new BufferedReader(f);
    }
    
    public String myReadLine() throws IOException {
        int i=0;
        StringBuilder s = new StringBuilder();
        while((i=br.read())!=-1&&(char)i!=''\r'') {
            if((char)i==''\n'') {continue;}
                s.append((char)i);    
        }
        if(s.length()==0) {
            return null;
        }
        return s.toString();
    }
}
模拟reader
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Scanner;

/*
 * 键盘录入一个文件夹路径,作为源文件夹;键盘录入一个文件夹路径,作为目标文件夹
    写代码将源文件夹拷贝到目标文件夹中
 */
public class Test {

    public static void main(String[] args) throws Exception {
        File src = getFile();//获取源文件
        File des = getFile();//获取目标文件
        copy(src,des);//进行复制

    }

    private static void copy(File src, File des) throws Exception {
        File newSrc = new File(des,src.getName());//在目标文件中新建与源文件同名的文件夹
        newSrc.mkdir();
        File[] listFiles = src.listFiles();
        if(listFiles!=null) {
            for(File subFile:listFiles) {
                if(subFile.isDirectory()) {
                    copy(subFile,newSrc);//如果子文件是文件夹,递归调用本方法
                }else {
                    File desFile = new File(newSrc,subFile.getName());//创建想要复制的文件
                    FileInputStream fis = new FileInputStream(subFile);//将源文件关联
                    BufferedInputStream bis = new BufferedInputStream(fis);//封装增强
                    FileOutputStream fos = new FileOutputStream(desFile);//目标文件关联
                    BufferedOutputStream bos = new BufferedOutputStream(fos);//封装增强
                    int b;
                    while((b=bis.read())!=-1) {
                        bos.write(b);
                    }
                    bos.close();
                    bis.close();
                }
            }
        }
        
    }

    private static File getFile() {
        Scanner sc = new Scanner(System.in);
        while(true) {
            String s = sc.nextLine();
            File file = new File(s);
            if(file.isDirectory()) {
                return file;
            }else {
                System.out.println("非法录入");
            }
        }
    }
    
}
练习文件夹拷贝
import java.io.File;
import java.util.Scanner;

//1、键盘录入一个文件夹路径,删除该文件夹(包含文件夹内容)
public class Test {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String s = sc.nextLine();
        File file = new File(s);
        deleteFile(file);
        
    }
    public static void deleteFile(File file) {        
        if(file.exists()) {
            File[] listFiles = file.listFiles();
            if(null==listFiles||listFiles.length==0) {
                file.delete();
                return;
            }
            for(File f:listFiles) {
                deleteFile(f);
            }
            file.delete();
        }
        
    }
}
File类和递归的使用
import java.io.File;
import java.util.Scanner;

//递归实现输入任意目录,列出文件以及文件夹
public class Test2 {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        while(true) {
            printAll(getFile());
            System.out.println("是否继续?继续请输入1,退出请输入0");
            Scanner sc = new Scanner(System.in);
            int i = sc.nextInt();
            if(i==1) {
                continue;
            }else {
                break;
            }
        }
    }
    public static File getFile() {
        Scanner sc = new Scanner(System.in);
        while(true) {
            System.out.println("请输入想要查询的文件路径");
            String s = sc.nextLine();
            File file = new File(s);
            if(file.exists()) {
                return file;
            }else {
                System.out.println("请重新输入");
            }
        }
    }
    public static void printAll(File file) {
        System.out.println(file.getName());
        if(file.isDirectory()) {
            File[] listFiles = file.listFiles();
            for(File subFile:listFiles) {
                printAll(subFile);
            }
        }
    }
}
递归和File类练习二
//对拷贝的效率进行查询,可以测试高效缓冲流的效率
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.util.Scanner;

public class Demo03 {

    public static void main(String[] args) throws Exception  {
        // TODO Auto-generated method stub
        File dsc = getFile();
        File src = getFile();
        FileInputStream f1 = new FileInputStream(src);
        BufferedInputStream bis  = new BufferedInputStream(f1);
        if(!dsc.exists()) {
            dsc.createNewFile();
        }
        FileOutputStream f2 = new FileOutputStream(dsc);
        BufferedOutputStream bos = new BufferedOutputStream(f2);
        byte[] b = new byte[1024];
        int len=0;
        long startTime = System.currentTimeMillis();
        while((len=bis.read(b))!=-1) {
            bos.write(b);
            double d = dsc.length();
            System.out.printf("文件已经复制了%.2f%%\n",d*100/src.length());
        }
        long endTime = System.currentTimeMillis();
        System.out.println("总共用时"+(endTime-startTime)/1000.000+"秒");
        bos.close();
        bis.close();
    }
    public static File getFile() {
        Scanner sc = new Scanner(System.in);
        while(true) {
            System.out.println("请输入想要查询的文件路径");
            String s = sc.nextLine();
            File file = new File(s);
            if(file.exists()) {
                return file;
            }else {
                System.out.println("请重新输入");
            }
        }
    }

}
高效缓冲流效率体验
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Scanner;

public class Test{

    public static void main(String[] args) throws IOException {
        InputStream is = System.in;
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        
        Scanner sc = new Scanner(System.in);
        
    }
}
System.in的原理
/*
 * 键盘录入一个文件路径,将该文件反转
    反转:第一行变成最后一行,第二行变成倒数第二行
 */
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.LinkedList;
import java.util.List;

public class Demo04 {

    public static void main(String[] args) throws Exception {
        File file = new File("aa.txt");
        FileReader fr = new FileReader(file);
        BufferedReader br = new BufferedReader(fr);
        File file2 = new File("bb.txt");
        FileWriter fw = new FileWriter(file2);
        BufferedWriter bw = new BufferedWriter(fw);
        LinkedList<String> list = new LinkedList<>();
        String str = null;
        while((str=br.readLine())!=null) {
            list.addFirst(str);
        }
        while(list.size()>0) {
            bw.write(list.removeFirst());
            bw.newLine();
            bw.flush();
        }
        bw.close();
        br.close();
    }

}
文件内容反转练习

 

 

java IO流 (二) IO流概述

java IO流 (二) IO流概述

1.流的分类
* 1.操作数据单位:字节流、字符流
* 2.数据的流向:输入流、输出流
* 3.流的角色:节点流、处理流

图示:

 

 


2.流的体系结构

 

 

说明:红框对应的是IO流中的4个抽象基类。
蓝框的流需要大家重点关注。

3.重点说明的几个流结构

 

 

4.输入、输出的标准化过程
4.1 输入过程
① 创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
② 创建相应的输入流,将File类的对象作为参数,传入流的构造器中
③ 具体的读入过程:
创建相应的byte[] 或 char[]。
④ 关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。
4.2 输出过程
① 创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在)
② 创建相应的输出流,将File类的对象作为参数,传入流的构造器中
③ 具体的写出过程:
write(char[]/byte[] buffer,0,len)
④ 关闭流资源
说明:程序中出现的异常需要使用try-catch-finally处理。

Java | IO流

Java | IO流

概述

Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。

流的分类

  • 按操作数据单位的不同分为:字节流(8bit)字符流(16 bit)
  • 按数据流的流向不同分为:输入流输出流
  • 按流的角色不同分为:节点流处理流

关于字节流和字符流的区别:

  • 读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
  • 处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
  • 字节流:一次读入或读出是8位二进制。
  • 字符流:一次读入或读出是16位二进制。

输入流和输出流

  • 输入流只能进行读操作
  • 输出流只能进行写操作

节点流和处理流

节点流:直接从数据源或者目的地读写数据

image.png

处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
image.png

Java IO流体系

Java中IO流体系如下表所示,最基本的四个抽象基类分别是:InputStreamOutputStreamReaderWriter。表格每一列的类都是继承与第一行的抽象基类的。

IO流体系图

常用的字符流

FileReader

通常一个流的使用由以下4个步骤组成:

  1. 提供File类的对象,指明要操作的文件
  2. 提供具体的流
  3. 根据不同流,进行不同的操作
  4. 流的关闭操作

比如以FileReader流为例,那么它的使用步骤是:

  1. 实例化File类的对象,指明要操作的文件
  2. 提供具体的流,FileReader流的实例化
  3. 进行数据的读入操作
  4. 流的关闭操作

虽然Java IO流体系有众多的类,但是所有的流都基本按照这几个步骤来使用的。下面记录一下FileReader的使用,数据的读入操作。

    @Test
    public void testFileReader() throws IOException { // 抛出异常
        // 1. 实例化File类对象,指明要操作的文件
        File file = new File("Hello.txt");
        // 2. 提供具体的流
        FileReader fr = new FileReader(file);
        // 3. 数据的读入
        // read():返回读入的一个字符,如果达到文件末尾,那么返回-1
        int data = fr.read();
        while(data != -1){
            System.out.print((char)data);
            data = fr.read();
        }
        // 4. 流的关闭操作
        fr.close();
    }

上面例子中,通过File类实例化了一个File对象,然后将其当做参数传入了FileReader类进行实例化,之后调用read()方法进行数据的读入,最后执行流的关闭。

关于上面代码有几个需要注意的点:

  • File file = new File("Hello.txt");这段代码使用的是相对路径,如果是使用IDEA进行编写的,那么这个相对路径在单元测试方法和main方法中有所区别。在单元测试方法中使用相对路径,那么相对的是模块的路径,而在main方法中相对的是项目的路径。比如,这里模块名Day07,这个模块下有文件Hello.txt,而模块位于项目JavaSenior下,那么File类实例化后的实例文件路径如下代码所示:
public class FileReaderTest {
    // 在main方法中,输出:D:\code\Java\JavaSenior\Hello.txt
    public static void main(String[] args) {
        File file = new File("Hello.txt");
        System.out.println(file.getAbsolutePath());
    }
    
     // 在单元测试方法中,输出:D:\code\Java\JavaSenior\Day07\Hello.txt
    @Test
    public void test4(){
        File file = new File("Hello.txt");
        System.out.println(file.getAbsolutePath());
    }
}
  • 由于创建流不能被Java垃圾回收机制所处理,所以需要手动进行流的关闭操作,但是由于异常,在步骤1,2,3可能出现异常导致第4步(流的关闭)不能被执行,导致资源不能及时回收,所以为了保证资源一定可以执行关闭操作,需要使用try-catch-finally进行处理,而不建议使用抛出的方式。所以,比较规范的流使用代码应该如下:
    @Test
    public void test2(){
        FileReader fr = null;
        try{
            File file = new File("Hello.txt");
            fr = new FileReader(file);
            int data;
            while ((data = fr.read()) != -1){
                System.out.println((char)data);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            try {
                if (fr != null){
                    fr.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
  • read()方法:读取单个字符。作为整数读取的字符,范围在0-65535之间(2个字节的Unicode码),如果已到达流的末尾,则返回-1。
  • read(char cbuf[]):将字符存入数组,并且返回本次读取的字符数,如果到达流的末尾,则返回-1。
    @Test
    public void test3()  {
        FileReader fr = null;
        try {
            // 1. File类的实例化
            File file = new File("Hello.txt");

            // 2. FileReader流的实例化
            fr = new FileReader(file);

            // 3. 读入的操作
            char[] cbuf = new char[5];
            int len;
             /*
             假如Hello.txt里的文件内容是helloworld123,这里的read(cbuf)指的是读取5个字符,
             即第一次读取hello,返回5,第二次读取world,返回5,
             第三次读取123,因为只有123了,返回3,第四次返回-1。
             所以3次循环,len变量的值为5,5,3,最后一次为-1。
             */
            while ((len = fr.read(cbuf)) != -1) {
                // 遍历操作错误的写法
//                for (int i = 0; i < arr.length; i++) {
//                    System.out.println(arr[i]);
//                }
                // 正确的遍历操作一:
//                for (int i = 0; i < len; i++) {
//                    System.out.print(arr[i]);
//                }

                // 错误的写法二:
//                String str = new String(arr);
//                System.out.println(str);

                // 正确的写法二:
                String str = new String(cbuf,0,len);
                System.out.print(str);
            }
        }catch (IOException e){
            e.printStackTrace();
        }finally {
            // 4. 流资源的关闭
            try {
                if (fr != null) {
                    fr.close();
                }
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

未完待续...

我们今天的关于java---IO流javaio流分为几种的分享就到这里,谢谢您的阅读,如果想了解更多关于Java & IO流、Java IO流、java IO流 (二) IO流概述、Java | IO流的相关信息,可以在本站进行搜索。

本文标签: