java_Day28_IO流和项目

IO流和项目

1. IO流

1.1 IO概述
IO参照物是当前程序使用内存
I
	input 从硬盘读取数据到内存!!!read 读
O 
	output 从内存写入数据到硬盘!!! write 写

直播为例:
	OBS推流软件 --> 浏览器 OBS输出数据到浏览器
	磊哥的键盘,屏幕,声音 --> OBS 对于OBS而言这是输入
	浏览器 --> 屏幕,耳机  对于浏览器而言,输出

对于Java而言:
	按照处理单位来看
	字节流
		所有的数据按照字节方式进行传输!!!
	字符流
		数据按照当前系统采用的编码集方式进行字符操作,该操作局限性很大!!!
		所能操作并且不会出现错误的文件,有且只有记事本打开无乱码的文本文件

组合
	字节输入流
	字节输出流
	字符输入流
	字符输出流
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 文件操作字节输入流
Constructor构造方法
	FileInputStream(String filePath);
		根据用户指定的文件路径创建对应的FileInputStream,文件操作输入字节流,
		如果文件不存在,抛出异常FileNotFoundException
	FileInputStream(File file);
		根据用户指定对应文件的File类对象,创建对应的FileInputStream,如果文件
		不存在,抛出异常FileNotFoundException

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

操作流程:
	1. 明确对应文件的路径,可以选择直接给予对应的String类型路径,或者创建对应的File类对象,作为参数
	2. 创建FileInputStream文件操作字节输入流,打开文件操作管道
	3. 从FileInputStream对象中使用方法,读取数据
	4. 关闭资源!!!FileInputStream类对象 ==> 水龙头!!!
package com.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.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));
	}
}
时间效率
	明显发现使用缓冲数组速度要远远高于单一字节读取操作
	读取24.8MB文件
		单一字节读取时间 47000 ms
		数组缓冲读取数据 19 ms
1.5 FileOutputStream 文件操作字节输出流
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,表示【追加写】,在文件末
		尾写入数据	
		
Method成员方法
	void write(int b);
		写入一个字节数据写入到文件中
	void write(byte[] buf);
		写入一个字节数组到文件中
	void write(byte[] buf, int off, int count);	
		写入一个字节数组到文件中,要求从off偏移位置开始,计数count

操作流程:
	1. 明确对应文件的路径,可以选择直接给予对应的String类型路径,或者创建对应的File类对象,作为参数
	2. 创建FileOutputStream文件操作输出字节流,打开文件操作管道
	3. 使用FileOutputStream对象写入数据到文件中
	4. 关闭资源!!!

【注意】
	1. FileOutputStream拥有创建文件的能力,在路径合法,且对应目录有写入权限下可以创建文件
	2. 区分删除写和追加写
	
package com.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();
	}
}
1.6 FileReader 文件操作字符输入流
Constructor构造方法
	FileReader(String filePath);	
		根据指定路径的文件创建对应的文件字符输入流对象,如果文件不存在,抛出异常
		FileNotFoundException
	FileReader(File file);
		根据指定路径的File类对象创建文件字符输入流对象,如果文件不存在,抛出异常
		FileNotFoundException
		
Method成员方法
	int read();
		从文件中读取一个字符数据,返回值为int类型,int类型数据中有且只有低十六位
		是有效数据,如果读取到文件末尾返回-1 EOF End Of File
	int read(char[] buf);
		从文件中读取数据到char类型缓冲数组buf,返回值是读取到字符个数。如果读取
		到文件末尾返回-1 EOF End Of File

操作流程:
	1. 明确需要读取数据的文件
	2. 创建FileReader对象,打开文件操作管道
	3. 使用FileReader类对象方法,读取文件数据
	4. 关闭资源
package com.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文件操作字符输出流
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,表示【追加写】,在文件末
		尾写入数据	
		
Method成员方法
	void write(int ch);
		写入一个字符数据写入到文件中
	void write(char[] buf);
		写入一个字符数组到文件中
	void write(char[] buf, int off, int count);	
		写入一个字符数组到文件中,要求从off偏移位置开始,计数count
	void write(String str);
    	写入一个字符串到文件中
	void write(String str, int offset, int count);
		写入一个字符串到文件中,要求从offset偏移位置开始,计数count
	

【注意】
	1. FileWriter拥有创建文件的能力,在路径合法,且对应目录有写入权限下可以创建文件
	2. 区分删除写和追加写
package com.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();
	}
}
1.8 关于字节流和字符流总结
1. 套路是一样的!!!
	明确文件
	打开管道
	操作文件
	关闭资源
2. 核心方法
	read 读取,输入
	write 写入,输出
3. 输出流有创建文件的能力。
4. 输出流需要注意是删除写还是追加写。
5. 一定要注意关闭资源!!!resource
1.9 文件拷贝对比
1.9.1 字符流字节流对比
字节流拷贝
package com.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();	
	}
}
字符流拷贝
package com.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 字符流操作效率问题
单字节拷贝操作
package com.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));
	}
}

缓冲数组形式操作
package com.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));
	}
}
有缓冲和无缓冲对比
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();                                                       
}                                                                     

【补充知识点 关于开发英文单词简拼】

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

猜你喜欢

转载自blog.csdn.net/zhu_fangyuan/article/details/106243142
今日推荐