IO流

IO流

1.IO流

1.1 IO流概述
  1. I与O

    IO流参照物是当前程序使用内存

    I:input 从硬盘读取数据到内存。read

    O:output 从内存写入数据到硬盘。write

    引例:以直播为例

    OBS推流软件 ==> 浏览器 :OBS输出数据到浏览器

    键盘、屏幕、声音 ==> OBS : 对于OBS而言这是输入

    浏览器 ==> 屏幕 : 对于浏览器而言,是输出

  2. 对于Java而言,数据按照处理单位来看,可分为:

    (1)字节流:所有的数据按照字节方式进行传输

    (2)字符流:数据按照当前系统采用的编码集方式进行字符操作,该操作局限性很大。所能操作并且不会出现错误的文件,有且只有记事本打开无乱码的文本文件

  3. IO与数据处理单位组合可分为四种操作模式:

    (1)字节输入流

    (2)字节输出流

    (3)字符输入流

    (4)字符输出流

1.2 缓存概念
  1. 缓存、缓冲有什么好处?

    一般的网站,第二次打开总要比第一次打开速度要快。

    说明:第一次加载网站打开的过程中,会对当前网页一些固定资源进行保存,可以提高用户在访问页面时的速度,优化体验

  2. 开发中使用缓冲、缓存可以有效提高文件操作效率

1.3 IO流分类
class InputStream 字节输入流基类
    class FileInputStream 文件操作字节输入流
class OutputStream 字节输出流基类
    class FileOutputStream 文件操作字节输出流
        
class Reader 字符输入流基类
    class FileReader 文件操作字符输入流
class Writer 字符输出流基类
    class FileWriter 文件操作字符输出流
        
需要学习的方法:
        read
        write
        
缓冲流:
BufferedInputStream		字节输入缓冲流
BufferedOutputStream	字节输出缓冲流
BufferedReader		字符输入缓冲流
BufferedWriter		字符输出缓冲流
1.4 FileInputStream文件操作字节输入流
  1. Constructor构造方法:

    FileInputStream(String filePath);
    	根据用户指定的文件路径创建对应的FileInputStream,文件操作输入字节流,如果文件不存在,抛出异常FileNotFoundException
    FileInputStream(File file);
    	根据用户指定对应文件的File类对象,创建对应的FileInputStream,如果文件不存在,抛出异常FileNotFoundException
  2. Method成员方法

    int read();
    	从文件中读取一个字节数据返回,如果读取到文件末尾,返回 -1,EOF End Of File
    int read(byte[] buf);【重点】
    	从文件中读取数据到缓冲数组buf中,返回值类型是从文件中读取到的字节个数,如果读取到文件末尾,返回-1,EOF End Of File
    
    读取数据的方法,在运行过程中出现了问题,抛出异常IOException
  3. 操作流程

    (1)明确对应文件的路径,可以选择直接给予对应的String类型路径,或者创建对应的File类对象,作为参数;

    (2)创建FileInputStream文件操作字节输入流,打开文件操作管道;

    (3)从FileInputStream对象中使用方法,读取数据;

    (4)关闭资源。(FileInputStream类对象可比作一个水龙头)

  4. 代码演示

    package com.qfedu.a_inputstream;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    /*
     * FileInputStream 演示
     */
    public class Demo1 {
    	public static void main(String[] args) throws IOException {
    		// 1. 明确操作文件
    		File file = new File("D:/aaa/1.txt");
    		
    		// 2. 创建文件操作输入字节流对象
    		FileInputStream fis = new FileInputStream(file);
    		
    		/*
    		 * 3. 读取数据
    		 * int read();
    		 * 		从文件中读取一个字节数据返回,返回值类型是int类型,但是
    		 * int类型数据中,有且只有低8位是有效数据
    		 */
    		int content = fis.read();
    		System.out.println((char) content);
    		content = fis.read();
    		System.out.println((char) content);
    		
    		// content = fis.read() content内容和-1比较,不等于-1继续
    		while ((content = fis.read()) != -1) {
    			System.out.println((char) content);
    		}
    		
    		// 4. 关闭资源
    		fis.close();
    	}
    }
    package com.qfedu.a_inputstream;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    /*
     * FileInputStream 演示 int read(byte[] buf);
     */
    public class Demo2 {
    	public static void main(String[] args) throws IOException {
    		long start = System.currentTimeMillis();
    		// 1. 明确操作文件
    		File file = new File("D:/aaa/1.txt");
    
    		// 2. 创建FileInputStream对象
    		FileInputStream fis = new FileInputStream(file);
    
    		/*
    		 * int read(byte[] buf); 该方法参数需要一个byte类型数组,这是一个缓冲数组。自定义数组容量
    		 * 但是一般情况,数组容量是1024的2的指数倍 1024 2048 4096 8192 返回值类型是缓冲数组中有效元素个数,读取到数据的字节个数,如果读取到
    		 * 文件末尾,返回-1
    		 */
    		// 3. 读取文件 4KB缓冲字节数组
    		byte[] buf = new byte[1024 * 4];
    		int length = -1;
    
    		while ((length = fis.read(buf)) != -1) {
    			// 字节数组转换成字符串
    			System.out.println(new String(buf, 0, length));
    		}
    
    		// 4. 关闭资源
    		fis.close();
    		
    
    		long end = System.currentTimeMillis();
    		
    		System.out.println("结束:" + (end - start));
    	}
    }
  5. 时间效率对比

    明显发现使用缓冲数组速度要远远高于单一字节读取操作

1.5 FileOutputStream文件操作字节输出流
  1. Constructor构造方法

    FileOutputStream(String filePath);
    	根据用户指定的路径,创建对应的FileOutputStream文件操作字节输出流对象,如果路径不合法,抛出异常FileNotFoundException
        采用写入数据到文件的方式是【删除写】,即文件内容清空,再写入数据。
            
    FileOutputStream(File file);
    	根据用户指定的File类对象,创建对应的FileOutputStream文件操作字节输出流对象,如果路径不合法,抛出异常FileNotFoundException
        采用写入数据到文件的方式是【删除写】,即文件内容清空,再写入数据。
            
    FileOutputStream(String filePath, boolean append);
    	根据用户指定的路径,创建对应的FileOutputStream文件操作字节输出流对象,如果路径不合法,抛出异常FileNotFoundException
        append参数是boolean类型,如果传入参数为true,表示【追加写】,即在文件末尾写入数据。
    FileOutputStream(File file, boolean append);
    	根据用户指定的File类对象,创建对应的FileOutputStream文件操作字节输出流对象,如果路径不合法,抛出异常FileNotFoundException
        append参数是boolean类型,如果传入参数为true,表示【追加写】,即在文件末尾写入数据
  2. Method成员方法

    void write(int b);
    	写一个字节数据到文件中
    void write(byte[] buf);
    	写一个字节数组到文件中
    void write(byte[] buf, int off, int count);
    	写一个字节数组到文件中,要求从off偏移位开始i,计数count
  3. 操作流程

    (1)明确对应文件的路径,可以选择直接给予对应的String类型路径,或者创建对应的File类对象,作为参数

    (2)创建FileOutputStream文件操作输出字节流,打开文件操作管道

    (3)使用FileOutputStream对象写入数据到文件中

    (4)关闭资源!!!

  4. 代码演示

    package com.qfedu.a_inputstream;
    
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
     * FileOutputStream演示
     */
    public class Demo3 {
    	public static void main(String[] args) throws IOException {
    		// 1. 明确操作文件
    		File file = new File("D:/aaa/疯狂打脸.txt");
    		
    		// 2. 创建FileOutputStream对象,默认使用删除写方式
    		FileOutputStream fos = new FileOutputStream(file, true);
    		
    		// 3. 写入数据到文件中
    		fos.write(49);
    		fos.write("今天骚磊同学,疯狂被打脸\n".getBytes());
    		fos.write("1234567".getBytes(), 0, 3);
    		// 4. 关闭资源
    		fos.close();
    	}
    }
  5. 小结

    (1)FileOutputStream拥有创建文件的能力,在路径合法且对应目录有写入权限的情况下可以创建文件

    (2)区分删除写追加写

1.6 FileReader文件操作字符输入流
  1. Constructor构造方法

    FileReader(String filePath);
    	根据指定的路径,创建对应的文件字符输入流对象,如果文件不存在,抛出异常FileNotFoundException
            
    FileReader(File file);
    	根据指定路径的File类对象创建文件字符输入流对象,如果文件不存在,抛出异常FileNotFoundException
  2. Method成员方法

    int read();
    	从文件中读取一个字符数据,返回值为int类型,int类型数据中有且只有低16位是有效数据,如果读取到文件末尾返回-1,EOF End Of File
    int read(char[] buf);
    	从文件中读取数据到char类型缓冲数组buf,返回值是读取到的字符个数,如果读取到文件末尾返回-1,EOF End Of File
  3. 操作流程

    (1)明确需要读取数据的文件

    (2)创建FileReader对象,打开文件操作管道

    (3)使用FileReader类对象方法,读取文件数据

    (4)关闭资源

  4. 代码演示

    package com.qfedu.a_inputstream;
    
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    
    /*
     * FileReade演示
     */
    public class Demo4 {
    	public static void main(String[] args) throws IOException {
    		// 1. 明确操作文件
    		File file = new File("D:/aaa/疯狂打脸.txt");
    		
    		// 2. 创建FileReader对象,打开文件管道
    		FileReader fr = new FileReader(file);
    		
    		// 3. 读取数据
    		// int content = fr.read();
    		// System.out.println((char) content);
    		char[] buf = new char[1024];
    		int count = -1;
    		
    		while ((count = fr.read(buf)) != -1) {
    			System.out.println(new String(buf, 0, count));
    		} 
    		
    		// 4. 关闭资源
    		fr.close();
    	}
    }
1.7 FileWriter文件操作字符输出流
  1. Constructor构造方法

    FileWriter(String filePath);
    	根据指定的路径,创建对应的FileWriter文件字符输出流对象,如果文件不存在,抛出异常FileNotFoundException
        采用写入数据到文件的方式,是删除写,即文件内容清空,再写入数据。
            
    FileWriter(File file);
    	根据指定路径的File类对象创建对应的FileWriter文件字符输出流对象,如果文件不存在,抛出异常FileNotFoundException
        采用写入数据到文件的方式,是删除写,即文件内容清空,再写入数据。
            
    FileWriter(String filePath, boolean append);
    	根据指定的路径,创建对应的FileWriter文件字符输出流对象,如果文件不存在,抛出异常FileNotFoundException
        append参数是boolean类型,如果传入参数为true,表示【追加写】,在文件末尾写入数据
            
    FileWriter(File file, boolean append);
    	根据指定路径的File类对象创建对应的FileWriter文件字符输出流对象,如果文件不存在,抛出异常FileNotFoundException
        append参数是boolean类型,如果传入参数为true,表示【追加写】,在文件末尾写入数据
  2. Method成员方法

    int write(int ch);
    	写一个字符数据到文件中
    int write(char[] buf);
    	写一个字符数组到文件中
    int write(char[] buf, int off, int count);
    	写一个字符数组到文件中,要求从off偏移位置开始,计数count
    void write(String str);
    	写一个字符串到文件中	
    void write(String str, int offset, int count);
    	写一个字符串到文件中,要求从offset偏移位置开始,计数count
  3. 操作流程

    (1)明确需要读取数据的文件

    (2)创建FileWriter对象,打开文件操作管道

    (3)使用FileWriter类对象方法,写入数据

    (4)关闭资源

  4. 代码演示

    package com.qfedu.a_inputstream;
    
    import java.io.File;
    import java.io.FileWriter;
    import java.io.IOException;
    
    /*
     * FileWriter
     */
    public class Demo5 {
    	public static void main(String[] args) throws IOException {
    		// 1. 明确文件
    		File file = new File("D:/aaa/今天被一发入魂了.txt");
    		
    		// 2. 创建FileWriter
    		FileWriter fw = new FileWriter(file);
    		
    		// 3. 写入数据
    		fw.write('1');
    		fw.write("我一个重坦被一个轻坦一发弹药架。。。".toCharArray());
    		fw.write("abcdefg".toCharArray(), 1, 3);
    		
    		fw.write('\n');
    		fw.write("胜利就在远方");
    		fw.write("0123456789", 5, 4);
    		
    		// 4. 关闭资源
    		fw.close();
    	}
    }
  5. 小结

    (1)FileWriter拥有创建文件的能力,在路径合法,且对应目录有写入权限下可以创建文件

    (2)注意区分删除写追加写

1.8 关于字符流和字节流总结
  1. 使用方式是一样的。(明确文件、打开管道、操作文件、关闭资源)
  2. 核心方法。Read(读取、输入)和Write(写入、输出)
  3. 输出流有创建文件的能力
  4. 输出流需要注意删除写与追加写
  5. 一定要注意关闭资源!resource
1.9 文件拷贝对比
1.9.1 字符流字节流对比
  1. 字节流拷贝
package com.qfedu.a_inputstream;

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

/*
 * 字节流拷贝文件
 */
public class Demo6 {
	public static void main(String[] args) throws IOException {
		// 南水北调 西气东输
		// 1. 明确数据源
		File srcFile = new File("D:/aaa/1.mp4");
		
		// 2. 明确目的地
		File destFile = new File("D:/aaa/byteStream.mp4");
		
		// 3. 创建FileInputStream输入流对象,读取源文件数据
		FileInputStream fis = new FileInputStream(srcFile);
		
		// 4. 创建FileOutputStream输出流对象,写入数据到目标文件
		FileOutputStream fos = new FileOutputStream(destFile);
		
		// 5. 完成数据拷贝过程,读取数据,写入数据
		byte[] buf = new byte[1024 * 16];
		int length = -1;
		
		while ((length = fis.read(buf)) != -1) {
			fos.write(buf, 0, length);
		}
		
		// 6. 关闭资源 先关后开
		fos.close();
		fis.close();	
	}
}
  1. 字符流拷贝
package com.qfedu.a_inputstream;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/*
 * 字符流拷贝
 * 无法拷贝非文本可视化文件
 */
public class Demo7 {
	public static void main(String[] args) throws IOException {
		// 南水北调 西气东输
		// 1. 明确数据源
		File srcFile = new File("D:/aaa/1.mp4");

		// 2. 明确目的地
		File destFile = new File("D:/aaa/charStream.mp4");
		
		// 3. 创建FileReader
		FileReader fr = new FileReader(srcFile);
		
		// 4. 创建FileWriter
		FileWriter fw = new FileWriter(destFile);
		
		// 5. 拷贝数据
		char[] buf = new char[1024 * 8];
		int length = -1;
		
		while ((length = fr.read(buf)) != -1) {
			fw.write(buf, 0, length);
		}

		// 6. 关闭资源
		fw.close();
		fr.close();
		
	}
}
1.9.2 字符流操作效率问题
  1. 单字节拷贝操作

    package com.qfedu.a_inputstream;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
     * 单字节拷贝数据
     */
    public class Demo8 {
    	public static void main(String[] args) throws IOException {
    		long start = System.currentTimeMillis();
    		// 南水北调 西气东输
    		// 1. 明确数据源
    		File srcFile = new File("D:/aaa/1.mp4");
    
    		// 2. 明确目的地
    		File destFile = new File("D:/aaa/byteStream.mp4");
    
    		// 3. 创建FileInputStream输入流对象,读取源文件数据
    		FileInputStream fis = new FileInputStream(srcFile);
    
    		// 4. 创建FileOutputStream输出流对象,写入数据到目标文件
    		FileOutputStream fos = new FileOutputStream(destFile);
    		
    		int content = -1;
    		while ((content = fis.read()) != -1) {
    			fos.write(content);
    		}
    		
    		fos.close();
    		fis.close();
    		
    		long end = System.currentTimeMillis();
    		
    		System.out.println("Time : " + (end - start));
    	}
    }
  2. 缓冲数组形式操作

    package com.qfedu.a_inputstream;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    /*
     * 字节流拷贝文件
     */
    public class Demo9 {
    	public static void main(String[] args) throws IOException {
    		long start = System.currentTimeMillis();
    		// 南水北调 西气东输
    		// 1. 明确数据源
    		File srcFile = new File("D:/aaa/1.mp4");
    
    		// 2. 明确目的地
    		File destFile = new File("D:/aaa/byteStream.mp4");
    
    		// 3. 创建FileInputStream输入流对象,读取源文件数据
    		FileInputStream fis = new FileInputStream(srcFile);
    
    		// 4. 创建FileOutputStream输出流对象,写入数据到目标文件
    		FileOutputStream fos = new FileOutputStream(destFile);
    
    		// 5. 完成数据拷贝过程,读取数据,写入数据
    		byte[] buf = new byte[1024 * 16];
    		int length = -1;
    
    		while ((length = fis.read(buf)) != -1) {
    			fos.write(buf, 0, length);
    		}
    
    		// 6. 关闭资源 先关后开
    		fos.close();
    		fis.close();
    		
    		long end = System.currentTimeMillis();
    
    		System.out.println("Time : " + (end - start));
    	}
    }
  3. 有缓冲和无缓冲对比

(1)在没有使用缓冲的情况下,每一次需要向磁盘申请一个字节数据,然后写入一个字节数据,这样会导致代码中打开和关闭磁盘的次数太多的情况,极大的影响效率。

(2)使用缓冲之后,降低了对于磁盘的开启和关闭次数,并且符合CPU操作磁盘的模式,CPU从磁盘读取数据是每一次4KB

2.项目

2.1 项目持久化操作

需要完成的方法:

(1)把StudentManager对象中存储的数据,写入到文件中

(2)从文件中读取内容,解析成Student对象,存储到StudentManager对象中

/**                                                                   
 * 保存数据到文件         
 *   
 * @param filePath 指定的文件路径   
 * @throws IOException IO异常 
 */                                                                   
public void saveDataToFile(String filePath) throws IOException {      
	// 字符缓冲输出流
	BufferedWriter bw = new BufferedWriter(new FileWriter(filePath)); 
	
	// 循环遍历StudentManager对象中,存储学生信息的ArrayList对象。      
    for (int i = 0; i < allStus.size(); i++) {                        
		// 得到学生信息数据字符串
		String data = allStus.get(i).getStudentData();   
        
		// 写入数据到文件
		bw.write(data);                                               
		// 在文件中加入一个换行,作为分隔标记
		bw.newLine();                                                 
	}                                                                 

	// 关闭资源
	bw.close();                                                       
}                                                                     
                                                                      
/**                                                                   
 * 从文件中读取数据到StudentManager对象中,存储到ArrayList内         
 *
 * @param filePath 指定的文件路径
 * @throws IOException IO异常
 */                                                                   
public void readDataFromFile(String filePath) throws IOException {    
	// 字符缓冲输入流
    BufferedReader br = new BufferedReader(new FileReader(filePath)); 
	String data = null;                                               
	                                                                
	// readLine从文件中读取一行数据,返回值类型是字符串类型
    while ((data = br.readLine()) != null) {                         
		// 利用学生类的工具方法解析数据字符串,得到学生对象
        Student stu = Student.parseStudent(data);                     

		// 存储学生对象到ArrayList中
        allStus.add(stu);                                             
	}                                                                 

	br.close();                                                       
} 

【补充知识点——Java开发中常用英文单词简写】

length  ==>  len
argument  ==>  arg
offset ==> off
buffer ==> buf
source ==> src
result ==> ret
image ==> img
destination ==> dest, dst

你可能感兴趣的:(IO流)