JavaSE模板化的IO流

IO流

首先说明一下本章主要学什么,IO流,其实就是升级版的File文件操作,在本章通过学习一些流,调用相应的方法,就可以实现从程序到文件,再从文件到程序的相应操作,而这一章节的代码也比较模板化,因此只需要记住基本的流,基本的使用方法,具体应用可以在项目中进行实践。

一、流的三种分类方式

1.流向

输入流、输出流

2.数据单位

字节流、字符流

3.流的角色

节点流、处理流

二、流的结构体系

在这里只提供一些常用常见的流

这个表其实也不用记,看一眼,知道有啥东西就行了,重点在后边。

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream
特殊流 DataInputStream DataOutputStream

三、输入、输出的标准化过程

模板的输入输出过程我用文件的字节输入输出流演示

1.输入过程

①创建File类的对象,指明读取的数据的来源(要求此文件一定存在)

File srcFile = new File("d:\\zyb.jpg");

②创建相应的输入流,将File类的对象作为参数,传入流的构造器中

FileInputStream fis = new FileInputStream(srcFile);

③读入过程:创建相应的byte[]或char[],并调用fis的read方法,放入循环中

byte[]buffer=new byte[10];
int len=0;
while((len=fis.read(buffer))!=-1){
    System.out.println(new String(buf,0,len));
}

④关闭流资源

fis.close();

说明:程序中出现的异常需要使用try-catch-finally处理

2.输出过程

①创建File对象,指明写出数据的位置(不要求此文件一定要存在)

File destFile = new File("d:\\zyb2.jpg");

②创建相应的输出流,将File类的对象作为参数,传入流的构造器中

FileOutputStream fos = new FileOutputStream(destFile);

③写出(创建buffer数组和len指针变量的过程和输入过程相同)

fos.write(buffer,0,len);

④关闭流资源

fos.close();

四、节点流

1.FileReader(字符输入流)

说明点:1、read()理解:返回读入的一个字符。如果到达文件末尾,则返回-1.

​ 2、异常处理:为了保证流资源一定可以执行关闭操作,需要使用try-catch-finally

​ 3、读入的文件一定要存在,否则会报FileNotFoundException异常

代码演示:

@Test
public void testFileReader1() throws IOException {

    //1.File类的实例化
    File file = new File("e:\\news2.txt");

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

    //3.读入文件的操作
    //read(char[] cubf):每次返回读入cubf数组中的字符个数,如果到达文件末尾,则返回-1
    char[]cbuf = new char[5];
    int len=0;
    while((len = fileReader.read(cbuf))!=-1){
        String str = new String(cbuf,0,len);
        System.out.println(str);
    }

    //4.资源的关闭
    fileReader.close();

}
2.FileWriter(字符输出流)

说明:1.输出到文件的操作,对应的File可以不存在,不会报异常

​ 2.File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。

​ File对应的硬盘中的文件如果存在:

有两种构造器,如果流使用的构造器是FileWriter(file)/FileWriter(file,false)则写入的信息会对原文件进行覆盖,比如原文件中已经含有字符“hello”,而我使用writer写入“world”,则最后文件的内容只有“world”。

​ 如果流使用的构造器是**FileWriter(file,true)**那么进行的是对原文件的续写操作,不会进行覆盖。比如原文件中已经含有字符“hello”,我写入“world”,则最后文件的内容为“hello world”。

代码演示:

@Test
public void testFileWriter() throws IOException {
    
    //1.提供File类的对象,指明写出到的文件
    File file = new File("hello1.txt");
    
    //2.提供FileWriter的对象,用于数据的写出
    FileWriter fw = new FileWriter(file, false);
    
    //3.写出到文件操作
    fw.write("wu zi bu xing\n");
    fw.write("edg nb!");
    
    //4.流资源的关闭
    fw.close();
    
}
3.文本文件的复制

文本文件的复制操作是通过在一个程序中同时调用输入流和输出流,进而实现创建一个新的文本,并对其进行赋值。

代码如下:

其中,srcFile是被复制的文件,destFile是将要创建,进行复制的文件。

@Test
public void testFileReaderWriter() throws IOException {
    
    //1.创建File类的对象,指明读入和写出的文件
    File srcFile = new File("hello1.txt");
    File destFile = new File("hello2.txt");
    
    //2.创建输入流和输出流的对象
    FileReader fr = new FileReader(srcFile);
    FileWriter fw = new FileWriter(destFile);
    
    //3.数据的读入和写出操作
    char[] cubf = new char[5];
    int len;
    while((len=fr.read(cubf))!=-1){
        fw.write(cubf,0,len);
    }
    
    //4.关闭流
    fw.close();
    fr.close();
}
4.FileInputStream / FileOutputStream(字节流)

​ 呃,这个和上面的字符流一样,没什么好说的,代码模板都一样,只需要在写入写出的时候把char[]数组换成byte[]数组就行了。。。

比较一下:对于文本文件(.txt,.java,.c,.cpp)之类的都使用字符流处理

​ 对于非文本文件(图片,音频,视频),使用字节流处理

五、缓冲流

1.缓冲流涉及到的类:

BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

2.作用

提高流的读取、写入速度

原理:内部提供了一个缓冲区。默认情况下是8kb

3.代码实现
·1BufferedInputStream、BufferedOutStream

该代码是用节点流+缓冲流实现图片的复制

其实缓冲流的代码跟上边节点流的代码模板一样,只不过多了一步将节点流的对象放入缓冲流的构造器中的步骤

@Test
public void BufferedStreamTest() throws IOException {
    
        //1.造文件
        File srcFile = new File("d:\\zyb.jpg");
        File destFile = new File("d:\\zyb2.jpg");

        //2.造节点流
        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);

        //3.造缓冲流
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        //4.复制:用bis读取,用bos写入
        byte[]buffer=new byte[10];
        int len=0;
        while((len=bis.read(buffer))!=-1) {
            bos.write(buffer, 0, len);
        }

        //5.资源关闭
        //要求:先关闭外层的流,再关闭内层的流
        bos.close();
        bis.close();
    }
·2BufferedReader、BufferedWriter

之前一直都是分开写,代码比较多,现在简写一下,试试将造文件的过程和造节点流的过程一起合并到造缓冲流的过程。

@Test
public void testBufferedReaderBufferedWriter() throws IOException {
    
        //1.将造文件,造节点流合成一步
        BufferedReader  bufferedReader = new BufferedReader(new FileReader(new File("e:\\news1.txt")));
        BufferedWriter   bufferedWriter = new BufferedWriter(new FileWriter(new File("e:\\news2.txt")));
       
        //2.数据的读入写出
        char[]cbuf=new char[1024];
        int len=0;
        while((len=bufferedReader.read(cbuf))!=-1){
            bufferedWriter.write(cbuf,0,len);
        }
        
        //3.关流
        bufferedReader.close();
        bufferedWriter.close();

    }

六、转换流

1.涉及到的类

InputStreamReader:将一个字节的输入流转换为字符的输入流

解码:字节、字节数组—>字符数组、字符串

OutputStreamWriter:将一个字符的输出流转换为字节的输出流

编码:字符数组、字符串—>字节、字节数组

编码决定解码!!!

2.作用

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

3.代码实现
·InputStreamReader

将字节输入流转换为字符输出流

呃,其实就多加了一步将字节输入流的对象放到转换流的构造器中而已

//转换输入流
@Test
public void test1() throws IOException {
    
    FileInputStream fileInputStream = new FileInputStream("e:\\news1.txt");						           
    //参数“UTF-8”指明了字符集(根据文件初始存的时候决定)
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream,"UTF-8");

    char[]cbuf=new char[1];
    int len;
    while((len=inputStreamReader.read(cbuf))!=-1){
        String str=new String(cbuf,0,len);
        System.out.print(str);
    }
    
    inputStreamReader.close();
}
·OutputStreamWriter

将字符输出流转换为字节输出流

写了这么多了,学了节点流,缓冲流,转换流,那现在咱们把这三个流都用到一起,综合升华一下,嘿嘿

这段代码的作用是实现文本的复制,就是将news1.txt中的文本信息复制到nesw3.txt中

快结束了,再来综合复习一下吧兄弟们

①造文件

②造节点流

③造缓冲流,提高运行效率

④造转换流,分别将输入流和输出流放入两个转换流中

⑤数组+循环 实现读入和写出

⑥关闭流

//转换输出流
@Test
public void test2() throws IOException{
	
    
    File file1 = new File("e:\\news1.txt");
    File file2 = new File("e:\\news3.txt");

    FileInputStream fileInputStream = new FileInputStream(file1);
    FileOutputStream fileOutputStream = new FileOutputStream(file2);
    
    BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
    BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);

    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"gbk");

    char[]cubf=new char[1];
    int len;
    while((len=inputStreamReader.read(cubf))!=-1){
        outputStreamWriter.write(cubf,0,len);
    }

    inputStreamReader.close();
    outputStreamWriter.close();
}

七、其它特殊流

1.标准的输入输出流

System.in:标准的输入流,默认从键盘输入 例如:new Scanner(System.in)

System.out:标准的输出流,默认从控制台输出 例如:System.out.println()

2.打印流

PrintStream和PrintWriter

说明:提供了一系列重载的print()和println()方法,用于多种数据类型的输出

​ System.out返回的是PrintStream的实例

3.数据流

DataInputStream和DataOutputStream

作用:用于读取或写出基本数据类型的变量或字符串

上面的三个流作为了解即可,不用深入

八、对象流

1.介绍

ObjectInputStream和ObjectOutputStream

作用:

ObjectInputStream:**内存中的对象—>存储中的文件、通过网络传输出去 ** 序列化过程

ObjectOutputStream:存储中的文件、通过网络接受过来—>内存中的对象 反序列化过程

2.对象的序列化机制

概念描述:

序列化过程:把内存中Java对象转换成平台无关的二进制流,从而把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。

反序列化过程:当其它程序获取了这种二进制流之后,就可以恢复成原来的Java对象

3.代码实现

序列化过程

​ 在这里说一点就是,java可以对自定义类进行序列化转换,但这个自定义类需要满足两个条件,第一个就是需要实现Serializable接口,这个接口是一个标识接口,不需要重写任何方法。第二个就是在类中需要提供一个全局常量serialVersionUID,其中这个全局常量的值必须进行自定义修改,任何值都可以。

  •    * @author 一只鱼zzz
     
       * @version 1.0
     
         * Person类需要满足一下的要求,方可序列化
     
         * 1.需要实现接口:Serializable(标识接口,无需重写方法)
     
         * 2.当前类需要提供一个全局常量:serialVersionUID
           */
           public class Person implements Serializable {
     
            public static final long serialVersionUID = 1231213123132L;
     
            private String name;
            private int age;
     
         public Person(String name, int age) {
                this.name = name;
                this.age = age;
            }
     
            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;
         }
     
         @Override
         public String toString() {
             return "Person{" +
                     "name='" + name + '\'' +
                     ", age=" + age +
                     '}';
         }
         }
    

/*
序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去
使用ObjectOutputStream实现
*/
@Test
public  void test1(){
   
       //1.造流造文件
       ObjectOutputStream oos = null;
   	try {
       oos = new ObjectOutputStream(new FileOutputStream("e:\\news1.dat"));
       //2.写
       oos.writeObject(new String("我爱轻大"));
       oos.flush();
       //3.刷新
       oos.writeObject(new Person("一只鱼zzzz",19));
       oos.flush();
   } catch (IOException e) {
       e.printStackTrace();
   } finally {
       //4.关
       try {
           oos.close();
       } catch (IOException e) {
           e.printStackTrace();
       }
   }
}

反序列化过程

@Test
public void  test2(){
    ObjectInputStream ois = null;
    try {
        ois = new ObjectInputStream(new FileInputStream("e:\\news1.dat"));

        Object obj=ois.readObject();
        String str=(String)obj;

        Person p = (Person) ois.readObject();

        System.out.println(p);
        System.out.println(str);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } finally {
        try {
            ois.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

九、RandomAccessFile流

1.介绍

(1)该类直接继承于Object类,实现了DataInput和DataOutput接口

(2)既可以作为一个输入流,又可以作为一个输出流

(3)如果作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。如果写出到的文件存在,则会对原文件内容进行覆盖。(默认情况下,从头覆盖)

(4)通过相关的操作,可以实现RandomAccessFile“插入数据”的功能

2.典型代码1
@Test
public void test1() throws IOException {

    RandomAccessFile raf1 = new RandomAccessFile(new File("hello1.txt"), "r");
    RandomAccessFile raf2 = new RandomAccessFile(new File("hello3.txt"), "rw");
    
    byte[]buffer = new byte[1024];
    int len;
    while((len=raf1.read(buffer))!=-1){
        raf2.write(buffer,0,len);
    }

    raf2.close();
    raf1.close();
}
3.典型代码2(插入效果)
@Test
public void test2() throws IOException {

    RandomAccessFile raf1 = new RandomAccessFile("hello3.txt", "rw");

    raf1.seek(3);//将指针调节到角标为3的位置

    //保存指针3后面的所有数据到StringBuilder中
    StringBuilder builder = new StringBuilder((int) new File("hello3.txt").length());

    byte[] buffer = new byte[20];
    int len;
    while((len=raf1.read(buffer))!=-1){
        builder.append(new String(buffer,0,len));
    }

    //调回指针,写入“xyz”
    raf1.seek(3);
    raf1.write("xyz".getBytes());

    //将StringBuilder中的数据写入到文件中
    raf1.write(builder.toString().getBytes());

    raf1.close();
}

你可能感兴趣的:(JavaSE,java)