(二)IO流

992 阅读11分钟

同步与异步:描述的是进程间的消息通知机制

  • 同步:当前任务必须等待上一个任务执行完成,

  • 异步:当前任务无需等待上一个任务完成,就可以执行下一个任务,

阻塞和非阻塞:描述线程在等待时的行为

  • 阻塞:在等待时,当前线程会进入阻塞状态,等待其他任务完成之后被唤醒

  • 非阻塞:在等待其他资源时,会一直轮询等待,不会进入休眠状态

1.javaIO流的分类

  • 按照流的流向分,可以分为输入流和输出流;

  • 按照操作单元划分,可以划分为字节流和字符流;

  • 按照流的角色划分为节点流和处理流。

Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

2.IO

能够说出IO流的分类和功能

能够使用字节输出流写出数据到文件

能够使用字节输入流读取数据到程序

能够理解读取数据read(byte[])方法的原理

能够使用字节流完成文件的复制

能够使用FileWirter写数据到文件

能够说出FileWriter中关闭和刷新方法的区别

能够使用FileWriter写数据的5个方法

能够使用FileWriter写数据实现换行和追加写

能够使用FileReader读数据

能够使用FileReader读数据一次一个字符数组

能够使用Properties的load方法加载文件中配置信息

IO模型:会先将字符读入linux缓冲区域,再读入用户线程的区域

1. I/O的分类

根据数据流向:输入流,输出流

根据数据类型:字节流,字符流

输入流输出流
字节流字节输入流 InputStream字节输出流 OutputStream
字符流字符输入流 Reader字符输出流 Writer

3. 字节流OutputStream/InputStream

(一)共性方法
  • public void close() :关闭此输出流并释放与此流相关联的任何系统资源。
  • public void flush() :刷新此输出流并强制任何缓冲的输出字节被写出。
  • public void write(byte[] b) :将 b.length字节从指定的字节数组写入此输出流。
  • public void write(byte[] b, int off, int len) :从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
  • public abstract void write(int b) :将指定的字节输出流。
(二) FileOutputStream类

OutputStream子类FileOutputStream文件输出流,用于将数据写出到文件

  • 构造方法

    public FileOutputStream(File file) :创建文件输出流以写入由指定的 File对象表示的文件。

    public FileOutputStream(String name) : 创建文件输出流以指定的名称写入文件。

    public class FileOutputStreamConstructor throws IOException {
    	public static void main(String[] args) {
    	// 使用File对象创建流对象
    	File file = new File("a.txt");
    	FileOutputStream fos = new FileOutputStream(file);
    	// 使用文件名称创建流对象
    	FileOutputStream fos = new FileOutputStream("b.txt");
    	}
    }
    
  • 写出字节流

    write(int b) 方法,每次可以写出一个字节数据 。

    File file = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt");
    FileOutputStream fos = new FileOutputStream(file);
    fos.write(97);
    fos.close();
    
    输出结果:a
    

    write(byte[] b) ,每次可以写出数组中的数据 。

    File file1 = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\2.txt");
    FileOutputStream fos1 = new FileOutputStream(file1);
    byte[] b="好好学啊".getBytes();
    fos1.write(b);
    fos1.close();
    
    输出结果:好好学啊
    

    write(byte[] b, int off, int len) ,每次写出从off索引开始,len个字节 。

    // 使用文件名称创建流对象
    FileOutputStream fos = new FileOutputStream("fos.txt");
    // 字符串转换为字节数组
    byte[] b = "abcde".getBytes();
    // 写出从索引2开始,2个字节。索引2是c,两个字节,也就是cd。
    fos.write(b,2,2);
    // 关闭资源
    fos.close();
    
    输出结果:cd
    
  • 数据追加续写

    public FileOutputStream(File file, boolean append) : 创建文件输出流以写入由指定的 File对象表示的文件。

    public FileOutputStream(String name, boolean append) : 创建文件输出流以指定的名称写入文件。 这两个构造方法,参数中都需要传入一个boolean类型的值, true 表示追加数据, false 表示清空原有数据。

            File file1 = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\2.txt");
            FileOutputStream fos1 = new FileOutputStream(file1,true);
            byte[] b1="好好学啊".getBytes();
            fos1.write(b1);
    
            File file2 = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\2.txt");
            FileOutputStream fos2 = new FileOutputStream(file2,true);
            byte[] b2="天天向上".getBytes();
            fos1.write(b2);
            fos1.close();
            fos2.close();
    
  • 写出换行

    Windows系统里,每行结尾是 回车+换行 ,即 \r\n ;

    Unix系统里,每行结尾只有 换行 ,即 \n ;

    Mac系统里,每行结尾是 回车 ,即 \r 。从 Mac OS X开始与Linux统一。

    public class FOSWrite {
    	public static void main(String[] args) throws IOException {
    		// 使用文件名称创建流对象
    		FileOutputStream fos = new FileOutputStream("fos.txt");
    		// 定义字节数组
    		byte[] words = {97,98,99,100,101};
    		// 遍历数组
    		for (int i = 0; i < words.length; i++) {
    		// 写出一个字节
    			fos.write(words[i]);
        	// 写出一个换行, 换行符号转成数组写出
        	fos.write("\r\n".getBytes());
    		}
            // 关闭资源
    	fos.close();
    	}
    }
    

(三)FileInputStream类

  • 构造方法

    FileInputStream(File file) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。

    FileInputStream(String name) : 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

    File file = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt");
    FileInputStream fis1=new FileInputStream(file);
    FileInputStream fis2=new FileInputStream("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt");
    
  • 读取字节数据

    read() 方法读取字节,每次可以读取一个字节的数据,提升为int类型,读取到文件末尾,返回 -1

    public class 输入字节流 {
        public static void main(String[] args) throws IOException {
            File file = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt");
            FileInputStream fis1=new FileInputStream(file);
            int b=0;
            while((b=fis1.read())!=-1){
                System.out.println((char)b);
            }
            System.out.println(b);
            fis1.close();
        }
    }
    

    read(byte[] b) ,每次读取b的长度个字节到数组中,返回读取到的有效字节个数,读取到末尾时,返回 -1

    public class 输入字节流 {
        public static void main(String[] args) throws IOException {
            File file = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt");
            FileInputStream fis1=new FileInputStream(file);
            byte[] b=new byte[2];
            int len=0;
            while((len =fis1.read(b))!=-1){
                System.out.println(len);
                System.out.println(new String(b,0,len));
            }
            fis1.close();
        }
    }
    

(四)案例复制图片

复制一张图片到目的地址

public class 输入字节流 {
    public static void main(String[] args) throws IOException {
        File fileInput = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\img.jpg");
        FileInputStream fis=new FileInputStream(fileInput);
        FileOutputStream fos = new FileOutputStream("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\bb\\img_result.jpg");
        byte[] b=new byte[1024];
        int len=0;  
        while((len=fis.read(b))!=-1){
            fos.write(b,0,len);
        }
        fos.close();
        fis.close();
    }
}

3.字符流Reader/Write

(一)字符输入流Reader

以字符为单位读写数据,专门用于处理文本文件

  • 共同方法

    public void close() :关闭此流并释放与此流相关联的任何系统资源。

    public int read() : 从输入流读取一个字符。

    public int read(char[] cbuf) : 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。

(二)FileReader类

  • 构造方法

    FileReader(File file) : 创建一个新的 FileReader ,给定要读取的File对象。

    FileReader(String fileName) : 创建一个新的 FileReader ,给定要读取的文件的名称。

    public class FileReaderConstructor throws IOException{
    	public static void main(String[] args) {
    		// 使用File对象创建流对象
    		File file = new File("a.txt");
    		FileReader fr = new FileReader(file);
    		// 使用文件名称创建流对象
    		FileReader fr = new FileReader("b.txt");
    	}
    }
    
  • 读取字符数据

    read 方法,每次可以读取一个字符的数据,提升为int类型,读取到文件末尾,返回 -1

    public class 输入字符流 {
        public static void main(String[] args) throws IOException {
            File file = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt");
            FileReader fir = new FileReader(file);
            
            int b=0;
            while((b=fir.read())!=-1){
                System.out.println((char)b);
            }
            fir.close();
        }
    }
    

    read(char[] cbuf) ,每次读取b的长度个字符到数组中,返回读取到的有效字符个数,读取到末尾时,返回 -1

    public class 输入字符流 {
        public static void main(String[] args) throws IOException {
            File file = new File("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt");
            FileReader fir = new FileReader(file);
            char[] buf=new char[2];
            int b=0;
            while((b=fir.read(buf))!=-1){
                System.out.println(new String(buf,0,b));
            }
            fir.close();
        }
    }
    

(三) 字符输出流FileWrite

  • 共同方法

    void write(int c) 写入单个字符。

    void write(char[] cbuf) 写入字符数组。

    abstract void write(char[] cbuf, int off, int len) 写入字符数组的某一部分,off数组的开始索引,len写的字符个数。

    void write(String str) 写入字符串。

    void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。

    void flush() 刷新该流的缓冲。

    void close() 关闭此流,但要先刷新它。

(四) FlieWriter类

  • 构造方法

    FileWriter(File file) : 创建一个新的 FileWriter,给定要读取的File对象。

    FileWriter(String fileName) : 创建一个新的 FileWriter,给定要读取的文件的名称。

    public class FileWriterConstructor {
    	public static void main(String[] args) throws IOException {
    		// 使用File对象创建流对象
    		File file = new File("a.txt");
    		FileWriter fw = new FileWriter(file);
    		// 使用文件名称创建流对象
    		FileWriter fw = new FileWriter("b.txt");
    	}
    }	
    
  • 写出字符数据

    write(int b) 方法,每次可以写出一个字符数据

    public class 输出字符流 {
        public static void main(String[] args) throws IOException {
            FileWriter fiw = new FileWriter("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\2.txt");
    
            fiw.write(97);
            fiw.write("a");
            fiw.write("你好啊");
            fiw.write(3000);
            fiw.close();
        }
    }
    

    write(char[] cbuf)

    write(char[] cbuf, int off, int len) ,每次可以写出字符数组中的数据,用法类似FileOutputStream

    public class 输出字符流 {
        public static void main(String[] args) throws IOException {
            FileWriter fiw = new FileWriter("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\2.txt");
            char[] chars="测试写入功能,看看是否可用".toCharArray();
            fiw.write(chars);
            fiw.write("\n");
            fiw.write(chars,0,chars.length);
            fiw.close();
        }
    }
    
  • 写出字符串

    write(String str) 和 write(String str, int off, int len) ,每次可以写出字符串中的数据,更为方便,

    public class FWWrite {
    	public static void main(String[] args) throws IOException {
    		// 使用文件名称创建流对象
    		FileWriter fw = new FileWriter("fw.txt");
    		// 字符串
    		String msg = "黑马程序员";
    		// 写出字符数组
    		fw.write(msg); //黑马程序员
    		// 写出从索引2开始,2个字节。索引2是'程',两个字节,也就是'程序'。
    		fw.write(msg,2,2); // 程序
    		// 关闭资源
    		fos.close();
    	}
    }
    
  • 刷新与关闭

    flush :刷新缓冲区,流对象可以继续使用。 close :先刷新缓冲区,然后通知系统释放资源。流对象不可以再被使用了。

    public class FWWrite {
    	public static void main(String[] args) throws IOException {
    		// 使用文件名称创建流对象
    		FileWriter fw = new FileWriter("fw.txt");
    		// 写出数据,通过flush
    		fw.write('刷'); // 写出第1个字符
    		fw.flush();
    		fw.write('新'); // 继续写出第2个字符,写出成功
    		fw.flush();
    		// 写出数据,通过close
    		fw.write('关'); // 写出第1个字符
    		fw.close();
    		fw.write('闭'); // 继续写出第2个字符,【报错】java.io.IOException: Stream closed
    		fw.close();
    	}
    }
    

    4.缓冲流NIO

  • 字节缓冲流: BufferedInputStream , BufferedOutputStream

  • 字符缓冲流: BufferedReader , BufferedWriter

缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。

(一) 字节缓冲流

  • 构造方法

    public BufferedInputStream(InputStream in) :创建一个 新的缓冲输入流。

    public BufferedOutputStream(OutputStream out) : 创建一个新的缓冲输出流。

    // 创建字节缓冲输入流
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
    // 创建字节缓冲输出流
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
    
  • 代码演示

    import java.io.*;
    
    public class 缓冲字节流 {
        public static void main(String[] args) throws IOException {
            BufferedInputStream bis = new BufferedInputStream(new FileInputStream("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\img.jpg"));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\bb\\img2.jpg"));
    
            int len=0;
            byte[] b=new byte[8*1024];
            while((len=bis.read(b))!=-1){
                bos.write(b,0,len);
            }
            bos.close();
            bis.close();
        }
    }
    

(二) 字符缓冲流

  • 构造方法 BufferedReader/BufferedWriter

    public BufferedReader(Reader in) :创建一个 新的缓冲输入流。

    public BufferedWriter(Writer out) : 创建一个新的缓冲输出流。

  • 特有方法

    BufferedReader: public String readLine() : 读一行文字。

    BufferedWriter: public void newLine() : 写一行行分隔符,由系统属性定义符号。

     public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new FileReader("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\2.txt"));
            String line=null;
            while((line=br.readLine())!=null){
                System.out.println(line);
                System.out.println("----------------------");
            }
    	    br.close();
     }
    
     public static void main(String[] args) throws IOException {
    
            BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Users\\YT\\Documents\\2020\\01java基础语法\\code\\aa\\1.txt"));
            bw.write("12345667",2,2);
            bw.newLine();
            bw.write("12345667",4,2);
            bw.newLine();
            bw.write("12345667",6,2);
    
            bw.close();
      }