IO流(上)

一、简述

  • IO是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。

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

  • Java.IO包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

二、流的分类

操作数据单位:字节流、字符流

  • 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
  • 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理

数据的流向:输入流、输出流

  • 输入input:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  • 输出output:将程序(内存)数据输出到磁盘、光盘等存储设备中。

流的角色:节点流、处理流

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

image-20200502092206789

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

IO流(上)_第1张图片

IO流(上)_第2张图片

三、IO流的体系分类

IO流(上)_第3张图片

红框为抽象基类,蓝框为常用IO流

1、常用的几个IO流结构

抽象基类 节点流(或文件流) 缓冲流(处理流的一种)
InputStream FileInputStream (read(byte[] buffer)) BufferedInputStream (read(byte[] buffer))
OutputSteam FileOutputStream (write(byte[] buffer,0,len) BufferedOutputStream (write(byte[] buffer,0,len) / flush()
Reader FileReader (read(char[] cbuf)) BufferedReader (read(char[] cbuf) / readLine())
Writer FileWriter (write(char[] cbuf,0,len) BufferedWriter (write(char[] cbuf,0,len) / flush()

2、对抽象基类的说明

抽象基类 字节流 字符流
输入流 InputSteam Reader
输出流 OutputSteam Writer
  • 说明:Java的lO流共涉及40多个类,实际上非常规则,都是从如下4个抽象基类派生的。

  • 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。

4、InputSteam & Reader

  • InputStream和Reader是所有输入流的基类。

  • InputStream(典型实现:FileInputStream)

    • int read()
    • int read(byte[] b)
    • int read(byte[] b,int off,int len)
  • Reader(典型实现:FileReader)

    • int read()
    • int read(char[] c)
    • int read(char[] c,int off,int len)
  • 程序中打开的文件IO资源不属于内存里的资源,垃圾回收机制无法回收该资源,所以应该显式关闭文件IO资源

  • FileInputStream从文件系统中的某个文件中获得输入字节。FileInputStream用于读取非文本数据之类的原始字节流。要读取字符流,需要使用 FileReader。

InputSteam:

  • int read()

    从输入流中读取数据的下一个字节。返回0到255范围内的int字节值。如果因为已经到达流末尾而没有可用的字节,则返回值-1。

  • int read(byte[] b)

    从此输入流中将最多b.length个字节的数据读入一个byte数组中。如果因为已经到达流末尾而没有可用的字节,则返回值-1.否则以整数形式返回实际读取的字节数。

  • int read(byte[] b,int off,int len)

    将输入流中最多len个数据字节读入byte数组。尝试读取len个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。如果因为流位于文件末尾而没有可用的字节,则返回值-1。

  • public void close throws IOException

    关闭此输入流并释放与该流关联的所有系统资源。

Reader:

  • int read()

    读取单个字符。作为整数读取的字符,范围在0到65535之间(0x00-0xffff)(2个字节的 Unicode码),如果已到达流的末尾,则返回-1。

  • int read(char[] cbuf)

    将字符读入数组。如果已到达流的末尾,则返回-1。否则返回本次读取的字符数。

  • int read(char[] cbuf,int off,int len)

    将字符读入数组的某一部分。存到数组cbuf中,从off处开始存储,最多读len个字符。如果已到达流的末尾,则返回-1。否则返回本次读取的字符数。

  • public void close throws IOException

    关闭此输入流并释放与该流关联的所有系统资源

5、OutputSteam & Writer

  • OutputStream和Writer也非常相似:
    • void write(int b/int c);
    • void write(byte[] b/char[] cbuf);
    • void write(byte[] b/char[] buff,int off,int len);
    • void flush();
    • void close();需要先刷新,再关闭此流
  • 因为字符流直接以字符作为操作单位,所以 Writer可以用字符串来替换字符数组,即以 String对象作为参数
    • void write(String str);
    • void write(String str,int off,int len);
  • FileOutputStream从文件系统中的某个文件中获得输出字节。FileOutputstream用于写出非文本数据之类的原始字节流。要写出字符流,需要使用 FileWriter

OutputStream:

  • void write(int b)

    将指定的字节写入此输出流。 write的常规协定是:向输出流写入一个字节。要写入的字节是参数b的八个低位。b的24个高位将被忽略。即写入0~255范围的

  • void write(byte[] b)

    将b.length个字节从指定的byte数组写入此输出流。write(b)的常规协定是:应该与调用wite(b,0,b.length)的效果完全相同。

  • void write(byte[] b,int off,int len)

    将指定byte数组中从偏移量off开始的len个字节写入此输出流。

  • public void flush()throws IOException

    刷新此输出流并强制写出所有缓冲的输出字节,调用此方法指示应将这些字节立即写入它们预期的目标。

  • public void close throws IOException

    关闭此输岀流并释放与该流关联的所有系统资源。

Writer:

  • void write(int c)

    写入单个字符。要写入的字符包含在给定整数值的16个低位中,16高位被忽略。即写入0到65535之间的 Unicode码。

  • void write(char[] cbuf)

    写入字符数组

  • void write(char[] cbuf,int off,int len)

    写入字符数组的某一部分。从off开始,写入len个字符

  • void write(String str)

    写入字符串。

  • void write(String str,int off,int len)

    写入字符串的某一部分。

  • void flush()

    刷新该流的缓冲,则立即将它们写入预期目标。

  • public void close throws IOException

    关闭此输出流并释放与该流关联的所有系统资源

四、输入、输出标准化过程

1、输入过程

  • 创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
  • 创建相应的输入流,将File类的对象作为参数,传入流的构造器中
  • 具体的读入过程:创建相应的byte[] 或 char[]。
  • 关闭流资源

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

2、输出过程

  • 创建File类的对象,指明写出的数据的位置。(不要求此文件一定要存在)
  • 创建相应的输出流,将File类的对象作为参数,传入流的构造器中
  • 具体的写出过程:write(char[]/byte[] buffer,0,len)
  • 关闭流资源

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

五、节点流(文件流)

1、文件的输入

  • 建立一个流对象,将已存在的一个文件加载进流 FileReader fr = new FileReader(new File("Test. txt"));
  • 创建一个临时存放数据的数组 char[] ch = new char[1024];
  • 调用流对象的读取方法将流中的数据读入到数组中。 fr.read(ch);
  • 关闭资源。 fr.close();
@Test
public void testFileReader1()  {
    FileReader fr = null;
    try {
        //1.File类的实例化
        File file = new File("hello.txt");

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

        //3.读入的操作
        //read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
        char[] cbuf = new char[5];
        int len;
        while((len = fr.read(cbuf)) != -1){
            String str = new String(cbuf,0,len);
            System.out.print(str);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fr != null){
            //4.资源的关闭
            try {
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

注意点:

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

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

  3. 读入的文件一定要存在,否则就会报FileNotFoundException。

2、文件的输出

  • 创建流对象,建立数据存放文件 File Writer fw = new File Writer(new File("Test.txt"))

  • 调用流对象的写入方法,将数据写入流 fw.write("HelloWord")

  • 关闭流资源,并将流中的数据清空到文件中。 fw.close();

@Test
public void testFileWriter() {
    FileWriter fw = null;
    try {
        //1.提供File类的对象,指明写出到的文件
        File file = new File("hello1.txt");

        //2.提供FileWriter的对象,用于数据的写出
        fw = new FileWriter(file,false);

        //3.写出的操作
        fw.write("I have a dream!\n");//   \n换行
        fw.write("you need to have a dream!");
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.流资源的关闭
        if(fw != null){
            try {
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3、练习:文本文件的复制操作

@Test
public void testFileReaderFileWriter() {
    FileReader fr = null;
    FileWriter fw = null;
    try {
        //1.创建File类的对象,指明读入和写出的文件
        File srcFile = new File("hello.txt");
        File destFile = new File("hello2.txt");

        //不能使用字符流来处理图片等字节数据
        //            File srcFile = new File("test.jpg");
        //            File destFile = new File("test1.jpg");

        //2.创建输入流和输出流的对象
        fr = new FileReader(srcFile);
        fw = new FileWriter(destFile);

        //3.数据的读入和写出操作
        char[] cbuf = new char[5];
        int len;//记录每次读入到cbuf数组中的字符的个数
        while((len = fr.read(cbuf)) != -1){
            //每次写出len个字符
            fw.write(cbuf,0,len);
        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        //4.关闭流资源
        try {
            if(fw != null)
                fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            if(fr != null)
                fr.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

4、文件字节流FileInputSteam和FileOutputSteam的使用

文件字节流操作与字符流操作类似,只是实例化对象操作和数据类型不同

//使用字节流FileInputStream处理文本文件,可能出现乱码。
@Test
public void testFileInputStream() {
    FileInputStream fis = null;
    try {
        //1. 造文件
        File file = new File("hello.txt");

        //2.造流
        fis = new FileInputStream(file);

        //3.读数据
        byte[] buffer = new byte[5];
        int len;//记录每次读取的字节的个数
        while((len = fis.read(buffer)) != -1){

            String str = new String(buffer,0,len);
            System.out.print(str);

        }
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if(fis != null){
            //4.关闭资源
            try {
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

5、注意点

  • 定义路径时,可以用“/”或“\\”。

  • 输出操作,对应的File可以不存在的。并不会报异常。

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

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

    • 如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖。
    • 如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容。
  • 读取文件时,必须保证文件存在,否则会报异常。

  • 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理

  • 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,...),使用字节流处理

你可能感兴趣的:(JAVA基础学习笔记,java)