IO加强

IO加强

1字符流

字符流只能读入文本,操作的是char,一个char等于二个bytes。

字符流有二个父类

1)重点为前二个子类

Reader(字符输入流)分为以下子类

*** BufferedReader*:基于缓冲区的读者**

*** InputStreamReader在字节流和字符流之间做转换的流。*

​ 子类有一个FileReader,是一个基于磁盘文件的字符输入

CharArrayReader:字符数组读者

PipedReader:管道读者

StringReader .. FilterReader ..

Writer(字符输出流)分为一下子类:

*** BufferedWriter***

*** OutputStreamWriter***

子类:FileWriter

PrintWriter:打印写者并提供换行。

CharArrayWriter

PipedWriter

FilterWriter .. StringWriter..

字符流的作用:与字节流相比效率更高,因为一个字符=二个字节,但局限性,应用不广。

1.1FileWriter

是一个基于字符的文件输出流,用于在磁盘中对文本文件做写操作。

构造方法和FileInputStream无大差别。

FileWriter(String name)

FileWriter(File file)

FileWriter(String name,boolean append)

FileWriter(File file,boolean append)

下面这个成员方法:Writer(int c)指传入一个ASCII码,传入文件变为ASCII码对应的字符。

场景:将字符写入磁盘

package com.hujesse.IO;
import java.io.FileWriter;
public class FileWriterTest1 {
    public static void main(String[] args) {
        try(
                FileWriter fw=new FileWriter("b.txt")
        ){
            char [] data = {'h','e','l','l','0'};
            // 将字符数组写入
            fw.write(data);
            //写入部分字符
            fw.writer(data,0,5);
            //写入单个字符
            fw.writer(100);
            //写入字符串
            fw.writer("Hujesse4");
            //写入部分字符串
            fw.writer("Hujesse4",0,5);
        }catch(Exception e){
            e.printStackTrace(); }
    }
}

1.2FileReader

基于字符的文件输入流,用来读取磁盘文件的数据。

 // FileReader 的源码
 public FileReader(String fileName) throws FileNotFoundException {
        super(new FileInputStream(fileName));
    }
 // FileInputStream的源码
     public FileInputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null);
    }
 //说明了字符流是基于字节流的

场景:创建FileReader对象读取数据

package com.hujesse.IO;
import java.io.FileReader;
import java.util.Arrays;
public class FileWriterTest1 {
    public static void main(String[] args) {
        try(
                FileReader fw=new FileReader("b.txt")
        ){
            // d定义一个字符数组,一次从磁盘读取多个
            char [] data = new char[32];
            fw.read(data);
            System.out.println(Arrays.toString(data));
        }catch(Exception e){
            e.printStackTrace(); } }}

1.3文本文件的拷贝

package com.hujesse.IO;
import java.io.FileReader;
import java.io.FileWriter;
public class FileWriterTest1 {
    public static void main(String[] args) {
        try(
                FileReader fr=new FileReader("b.txt");
                FileWriter fw=new FileWriter("b_copy.txt");
        ){
            char []buffer = new char[32];
            int len;
            while ((len=fr.read(buffer))!=-1){
                fw.write(buffer,0,len);
            }
        }catch(Exception e){
            e.printStackTrace(); } }}

2缓冲流

2.1相关概念

流的分类

流的流向:输入流和输出流

按照数据类型:字节流和字符流

按照功能:基础流和装饰流(处理流)

什么是基础流:FileInputStream和FileOutputStream之间操作磁盘的。

什么是装饰流:对基础流做了一个包装,例如FileReader对FileInputStream做了一个装饰,在创建FileReader同时创建了FileInputStream

2.2带有缓冲区的装饰流(基于字节)

带有缓冲区的好处(由来..whatever):内存读取数据快,磁盘读取数据慢,需要一个缓冲区来匹配速度

基于字节的装饰流:

BufferedInputStream & BufferedOutputStream

2.2.1BufferedInputStream

1)**BufferedInputStream 在基础流之上多了一个基于字节数组的缓冲区,默认大小为8192bytes。
2)缓冲输入流相对于普通输入流的优势是,它提供了一个缓冲数组,每次调用read方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源(譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,最后再将缓冲区中的内容部分或全部返回给用户.由于从缓冲区里读取数据远比直接从物理数据源(譬如文件)读取速度快。
3) 里面有二个属性,pos(position)和count,当pos==count,说明读取完毕了

场景:使用缓冲输入流读取磁盘数据并打印

package com.hujesse.IO;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
public class BufferedInputTest {
    public static void main(String[] args) {
        try(
                BufferedInputStream bu = new BufferedInputStream(new FileInputStream("a.txt"));
                ){
            //每次读取1024个字节
            byte[] data = new byte[1024];
            int len = 0;
            // 理解String StringBuffer StringBuilder的区别;capacity容积
            StringBuilder sb = new StringBuilder(500);
            while ((len=bu.read(data))!=-1){
                //将字节数组转换为字符串
                String str = new String(data,0,len);
                //将字符串追加到StringBuilder
                sb.append(str);
            }
            System.out.println(sb.toString());
        }catch (Exception e){
            e.printStackTrace(); } }}

2.2.2BufferedOutputStream

BufferedOutputStream是一个缓冲输出流,内部也有一个缓冲区,在写数据的时候,会将数据写入缓冲区直到写满,再讲缓冲区的数据一次性写入磁盘。

场景:使用字节缓冲流拷贝图片
package com.hujesse.IO;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class BufferedOutPutTest {
    public static void main(String[] args) {
        try (
                BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream("BufferCopy.jpg"));
                BufferedInputStream in = new BufferedInputStream(new FileInputStream("D:\\timg.jpg"));
        ) {
            byte[] data = new byte[1024];
            int len = 0;
            while ((len = in.read(data)) != -1) {
                os.write(data, 0, len);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } }}
// 和FileInputStream操作真没什么区别

唯一需要注意的是BufferOutputStream(OutputStream out)需要传入对象,子类也可以。

2.3带有缓冲区的装饰流(基于字符)

他们内部也有一个缓冲区,这个缓冲区是一个char[],默认长度为8192

2.3.1BufferedReader

构造方法:BufferedReader(Reader):创建一个基于字符的缓冲流,参数是一个Reader的子类,例如:FileReader。

它除了支持read()的方法外还支持

readLine():读取缓冲区里的一行数据,读到\r\n就会结束。

2.3.2 BufferedWriter

构造方法:BufferWriter(Writer):创建一个基于字符的缓冲流,参数是一个Writer的子类,例如:FileWriter。

还支持newLine():写入\r\n换行

场景:使用字符缓冲流进行文件的copy&paste
package com.hujesse.IO;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
// bufferReader BUfferedWriter进行copy& paste
public class BufferRead {
    public static void main(String[] args) {
        try(
                BufferedReader bf = new BufferedReader(new FileReader("D:\\bia.txt"));
                BufferedWriter bw = new BufferedWriter(new FileWriter("copyChar.txt"));
                ){
            // 用一个String类型接受数据
                    String line = null;
                    while ((line=bf.readLine())!=null){
                        bw.write(line);
                        //换行
                        bw.newLine();
                    }
        }catch (Exception e){
            e.printStackTrace(); } }}

3内存流(重点)

特征:数据的读和写都在内存中完成,可以将数据写入内存中,也可以从内存中读取数据。

3.1 ByteArrayOutputStream

基于字节的内存输出流,它是一个基础流,主要用于将程序中的数据转换为字节数组,然后写入流中。

构造方法如下:

ByteArrayOutputStream()无参构造方法,用来创建字节数组输出流对象。

ByteArrayOutputStream(int size)同上,不过参数size是字节数组的长度。

场景:定义一个变量,将其转换为字节数组,然后将其写入到ByteArrayOutputStream流里面

package com.hujesse.IO;
import java.io.ByteArrayOutputStream;
public class ByteArrayOutStream {
    public static void main(String[] args) {
        try (
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                ) {
            String str = "helloIO";
            bo.write(str.getBytes());
            //bo.flush(); JVM自动帮我门做了这种事
        } catch (Exception e) {
            e.printStackTrace(); } }}

3.2 ByteArrayInputStream

是一个字节数组输入流,也是一个基础流,主要用于将内存的数据读取到程序中。

场景:定义一个变量,将其转换为字节数组,然后将其写入到ByteArrayInputStream流,最后调取类的方法读取数据

package com.hujesse.IO;
import java.io.ByteArrayInputStream;
public class ArrayInputStreamTest {
    public static void main(String[] args) {
        try(
                ByteArrayInputStream bi = new ByteArrayInputStream("test".getBytes());
                ){
                    int data = bi.read();
                System.out.println((char)data);
        }catch(Exception e){
            e.printStackTrace();
        } }}
// FileInputStream(String name)读取磁盘里面的数据
//ByteArrayInputStream(byte[])读取内存中的数据
综合案例:将百度服务器的logo下载到本地磁盘

package com.hujesse.IO;
/**
 * 场景:从百度服务器下载资源
 * 创建URL对象,指定百度服务器的地址
 * 打开URL链接
 * 读取百度服务器数据,将读取的数据存储到内存流
 * 创建FileInputStream,将内存流数据写到本地磁盘
 */
import java.io.*;
import java.net.URL;
public class ArrayInputStreamTest {
    public static void main(String[] args) throws Exception{
        URL url = new URL("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
        try(
                //url.openStream()相当于在浏览器输入服务器地址,然后回车
                InputStream in = url.openStream();
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                ){
            // 使用输入流读取百度服务器图片,将读取的数据放进内存流
                    byte[] bufffer = new byte[1024];
                    int len = 0;
                    while ((len=in.read(bufffer))!=-1){
                        bo.write(bufffer,0,len); }
                    bo.flush();
                    // 获取内存流里面的字节数
                    try(
                            FileOutputStream fo = new FileOutputStream(new File("Logo.png"));
                            ){
                        //bo.toByteArray()将内存流里面的数据转换为字节数组
                        byte [] data2 = bo.toByteArray();
                        fo.write(data2);
                    }catch(Exception e
                    ){
                        e.printStackTrace();
                    }
        }catch (Exception e){
            e.printStackTrace(); } }}
//最主要的是内存流有个方法 byteArrayOutputStream.toByteArray()
//可以将内存流里面的的数据全部转换为字节数组

4对象输入和输出流

4.1 ObjectInputStream

是一个基于字节的对象输入流,同时也是一个装饰流,主要用于读取内存中的对象

构造方法:ObjectInputStream(InputStream)

1)工作中可以使用对象输入和输出流来完成对象的克隆
2)什么叫对象的克隆?在原始对象的基础上繁殖新对象,新对象数据和原对象一模一样

4.2 ObjectOutputStream

是一个基于字节的对象输出流,同时也是一个装饰流,主要用于读取内存中的对象

构造方法:ObjectOutputStream(outputStream)

场景:对象的克隆

package com.hujesse.IO;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectInPutStreamCLONE {
    public static void main(String[] args) {
        Student hujesse4 = new Student(20, "hujesse4");
        try (
                //创建原始输出流对象,将字节数组输出流注入到对象输出流里面
                ByteArrayOutputStream bo= new ByteArrayOutputStream();
                ObjectOutputStream op = new ObjectOutputStream(bo);
        ) {
            //将对象写入内存
            op.writeObject(hujesse4);
            try(
                    // 注意把输出流的内容转换为对象数组传给输入流.bo.toByteArray()存储了原始数据
                    ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
                    ObjectInputStream ob = new ObjectInputStream(bi);
                    ){
                   Object stuClone = ob.readObject();
                System.out.println(stuClone);
            }catch (Exception e){
                System.out.println("clone Object failed");
                e.printStackTrace();
            }
        } catch (Exception e) {
            System.out.println("clone Object failed");
            e.printStackTrace(); } }}

package com.hujesse.IO;
import java.io.Serializable;
//参与clone的对象必须继承implements Serializable接口,否则抛出异常
public class Student implements Serializable {
    private int age;
    private String name;
    /* getters and setters */

小改进,写成一个静态方法

    public static Object ObejctClone (Object obj)throws Exception{
        try (
                ByteArrayOutputStream bo = new ByteArrayOutputStream();
                ObjectOutputStream oo = new ObjectOutputStream(bo);
                ) {
            oo.writeObject(obj);
            try (
                    ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
                    ObjectInputStream oi = new ObjectInputStream(bi);
            ){
                return oi.readObject();
            } } }

5转换流

5.1 InputStreamReader

它是一个连接字节流和字符流之间的桥梁,也是一个输入流

// 为什么需要转换流 ---

为了解决设备之间编码方式不统一的问题

场景:将D盘目录下的一个文本文件拷贝,可它使用的是GBK编码,但IDEA使用的是UTF-8编码,拷贝会出现乱码。

什么时候用呢:即源头编码和目标编码不一致时,使用转换流(指定编码格式)即解决乱码

但是工作中一般定义有缓冲区的转换流

new BufferedReader(new InputStreamReader(new FileInputStream("D:\\bia.txt"),"GBK"))
new BufferedWriter(new InputStreamWriter(new FileOutputStream("copy.txt"),"GBK"))

场景:使用带有缓冲区的读者写者配合转换流进行文件的复制粘贴

package com.hujesse.IO;
import java.io.*;
public class InputStreamReaderTES {
    public static void main(String[] args) {
     try(
             BufferedReader bf=new BufferedReader(new InputStreamReader(new FileInputStream("D:\\bia.txt"),"UTF-8"));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("copy.txt"),"UTF-8"));
             ){
         String line = null;
         while((line=bf.readLine())!=null){
             bw.write(line);
             bw.newLine();
         }
     }catch(Exception e){
         e.printStackTrace(); } }}

5.2 OutputStreamWriter

它是一个连接字节流和字符流之间的桥梁,也是一个输出流

见上个场景

6读写基本数据类型

6.1 DataInputStream

构造函数DataInputStream(InputStream )

还提供了一些读写的方法

readint()读整数

readFloat()读单精度浮点小数

readDouble()读双精度浮点小数

readBoolean()读取Boolean

readChar()读字符

readUTF()读字符串

6.2 DataOutputStream

构造函数DataOutputStream(OutputStream)

还提供了一些写的方法

writeInt(int);写入整数

writeFloat(Float):写入单精度浮点数



场景:定义一个Student数组,使用DataOutputStream将数据写入磁盘,然后用DataInoutStream读写出来并打印;

package com.hujesse.IO;
import java.io.*;
public class DataInOutputStreamTest {
    private static Student[] students = {
            new Student(20,"hujesse"),
            new Student(13,"cousin")};
    public static void main(String[] args)
    {
        try(
            DataOutputStream dot = new DataOutputStream(new FileOutputStream(new File("student")))
        ){
            for(Student stu:students){
                dot.writeInt(stu.getAge());
                dot.writeUTF(stu.getName());
            }
          try(
                  DataInputStream dit = new DataInputStream(new FileInputStream("student"));
                  ){
              for(int i =0;i<students.length;i++){
                  int age = dit.readInt();
                  String name = dit.readUTF();
                  System.out.println(age);
                  System.out.println(name);
              }
          }catch (Exception e){e.printStackTrace();
          }
        }catch (Exception e){e.printStackTrace();
        } }}

7打印流(了解)

PrintWriter:就是BufferedWriter + 换行

PrintWriter时一个字符流同时也是一个装饰流提供了换行的功能;

方法为:pw.println(args);

小知识

1)boolean不是布尔类型,而是logic(逻辑)类型
posted @ 2021-01-20 19:23  能借我十块钱吗  阅读(89)  评论(0编辑  收藏  举报