相关链接
目录
P13 【其他】异常,File,IO,字节(符)流,字节(符)缓冲流,转换流
1 异常
1.1 异常的概述
- 异常的概念
- 异常(Exception类):就是程序出现了不正常的情况。下面举例:
- 【ArithmeticException】:当出现异常的运算条件(例如一个整数“除以零”)时,抛出此异常(此类的一个实例)。
- 常见的异常有
- IndexOutOfBoundsException : 数组越界异常,访问的元素超出了数组范围
- NullPointerException : 空指针异常,一般在使用对象的方法时会出现,对象为null,所以不能调用该对象的方法。
- StringIndexOutOfBoundsException : 字符串索引越界异常,String类也可以视为数组,可以理解为字符类型数组越界异常。
- 在使用String类的如 charAt(int index); subString(int beginIndex, int endIndex); 方法时,index参数超过String数组本身范围,则会报出这个错误。
- 异常的体系的介绍
- Throwable 类是 Java 语言中所有错误或异常的超类。
- Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。
- 也就是说针对程序发生了Error的情况,Java程序本身是无能为力的,比如说:硬件层面的问题,内存不足等。
- 所以,针对Error的问题我们不处理。
- Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。
- 也就是说针对程序发生了Exception的情况,是我们需要处理的问题。
- Exception的分类
- 运行期的异常(RunTimeException):在编译期是不处理的,在程序运行时候出现了问题,需要我们回来修改代码。
- 编译期的异常(非RunTimeException):在编译期就必须处理,否则程序不能通过编译,就更不能正常的执行了。
- 异常的两种处理方式
- 方式一: try catch (快捷键 ctrl + alt + t)
try { //尝试对此部分代码捕获异常 } catch (Exception e) { //捕获异常后的处理逻辑 //e.printStackTrace(); //默认处理方式打印异常信息 } finally { //无论是否捕获异常,都会执行 }
- 方式二:throws Exception
- 如果你采用了throws这种方案,将来谁调用,还得进行处理。
- 运行时异常可以不用处理,出现问题后我们需要回来修改代码。
//以IOException为例,只有使用BufferedReader就会出现找不到文件IO异常,需要进行处理 public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("name.txt")); }
- 方式一: try catch (快捷键 ctrl + alt + t)
1.2 JVM默认处理异常方式
- 处理方案
- A:把异常的名称,异常的原因,异常出现的位置等信息在控制台输出
- B:让程序停止执行
案例代码一 JVM默认处理异常方式
package com.groupies.base.day13;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction JVM默认处理异常方式
*
* 处理方案:
* A:把异常的名称,异常的原因,异常出现的位置等信息在控制台输出
* B:让程序停止执行
*/
public class Demo1Exception {
public static void main(String[] args) {
/*
程序开始执行
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.groupies.base.day13.Demo1Exception.method(Demo1Exception.java:28)
at com.groupies.base.day13.Demo1Exception.main(Demo1Exception.java:21)
*/
System.out.println("程序开始执行");
method();//【报错定位】第21行
System.out.println("程序结束执行");
}
public static void method(){
int a = 10;
int b = 0;
System.out.println(a / b);//【报错定位】第28行
}
}
1.3 编译时异常&运行时异常 区别
- Java中的异常被分为两大类:编译时异常和运行时异常。
- 所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常都是编译时异常;
- 编译时异常:Java程序必须显示处理,否则程序就会发生错误的一个提示,无法通过编译;
- 运行时异常:Java程序无需显示处理,也可以和编译时异常一样处理。
1.4 异常处理1:try catch
- 异常的两种处理方式
- 方式一: try catch (快捷键 ctrl + alt + t)
- 执行流程
- 程序从try开始执行,执行到哪里出现了问题,就会跳转到catch里面执行;
- 执行完毕后,程序还能继续往下执行;
- 无论是否捕获异常 都一定会执行finally部分的代码。
try { //尝试对此部分代码捕获异常 } catch (Exception e) { //捕获异常后的处理逻辑 //e.printStackTrace(); //默认处理方式打印异常信息 } finally { //无论是否捕获异常,都会执行 }
- 执行流程
- 方式二:throws Exception
- 如果你采用了throws这种方案,将来谁调用,还得进行处理。
- 运行时异常可以不用处理,出现问题后我们需要回来修改代码。
//以IOException为例,只有使用BufferedReader就会出现找不到文件IO异常,需要进行处理 public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new FileReader("name.txt")); }
- try catch 获异常后, 如何处理?
public void printStackTrace()
:把异常的错误信息输出在了控制台。- 在实际开发中,我们遇见了异常,会给出一个页面进行提示,而我们目前做不了,
- 所以,就用异常对象调用printStackTrace()就可以了。
- try…catch处理方式&JVM的默认处理方式有什么不同?
- 首先要明确try…cathc处理方式的特点, 产生了问题, 是自己将问题处理掉, 不影响后续代码的运行.
- JVM默认处理方式是将程序终止, 并将异常信息打印在控制台.
- 但这种方式很显然用户体验度不佳, 所以这时候就可以考虑使用try…cathc将问题捕获并处理掉.
- 这样就不会影响程序的继续执行了
案例代码二 try…catch处理异常
package com.groupies.base.day13;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction try..catch处理异常
*
* 为什么要有throws处理方式?
* 我们通过try...catch可以对异常进行处理了,但是并不是所有的时候我们都有权限进行异常的处理。
* 也就是说,有些时候我们处理不了,但是,这个时候异常时存在的,不处理也不行,怎么办?
* 这个时候,Java就提供了throws的处理方案。
*
* try..catch的格式和执行流程为
* 格式:
* try {
* 可能出现异常的代码;
* }catch(异常类名 变量名) {
* 异常的处理代码;
* }
*
* 执行流程:
* 程序从try开始执行,执行到哪里出现了问题,就会跳转到catch里面执行。
* 执行完毕后,程序还能继续往下执行。
*
* 捕获异常后, 如何处理?
* public void printStackTrace():把异常的错误信息输出在了控制台。
* 在实际开发中,我们遇见了异常,会给出一个页面进行提示,而我们目前做不了,
* 所以,就用异常对象调用printStackTrace()就可以了。
*
* try..catch处理方式&JVM的默认处理方式有什么不同
* 首先要明确try..cathc处理方式的特点, 产生了问题, 是自己将问题处理掉, 不影响后续代码的运行.
* JVM默认处理方式是将程序终止, 并将异常信息打印在控制台.
* 但这种方式很显然用户体验度不佳, 所以这时候就可以考虑使用try..cathc将问题捕获并处理掉.
* 这样就不会影响程序的继续执行了
*/
public class Demo2TryCatch {
public static void main(String[] args) {
System.out.println("-----程序开始执行-----");
System.out.println("method: 编译时异常");
method();//日期格式不合法,请重新输入
System.out.println("method2: 运行时异常");
method2();//除数不能为0
System.out.println("-----程序结束执行-----");
}
//编译时异常ParseException
public static void method() {
//String s = "2088-08-08";
String s = "abcd";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = null;
try {
//如果不抛出异常,也不使用try catch捕获异常,则会提示如下信息:不能通过编译
//java: 未报告的异常错误java.text.ParseException; 必须对其进行捕获或声明以便抛出
d = sdf.parse(s);
} catch (ParseException e) {
//e.printStackTrace();//不打印异常信息
System.out.println("日期格式不合法,请重新输入");
}
System.out.println(d);
}
//运行时异常
public static void method2() {
try {
int a = 10;
int b = 0;
System.out.println(a / b);
} catch (ArithmeticException e) {
//e.printStackTrace();//不打印异常信息
System.out.println("除数不能为0");
}
}
}
1.5 异常处理2:throws
- 为什么要有throws处理方式?
- 我们通过try…catch可以对异常进行处理了,但是并不是所有的时候我们都有权限进行异常的处理。
- 也就是说,有些时候我们处理不了,但是,这个时候异常时存在的,不处理也不行,怎么办?
- 这个时候,Java就提供了throws的处理方案。
- throws使用的格式
- throws 异常类名
- 注意:这个格式必须跟在方法的括号的后面
//实例 public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new FileReader("name.txt")); }
- throws使用的注意事项?
- 编译时异常时必须要进行处理的,两种处理方案:try…catch…或者throws
- 如果你采用了throws这种方案,将来谁调用,还得进行处理。
- 运行时异常可以不用处理,出现问题后我们需要回来修改代码。
案例代码三 throws处理异常
package com.groupies.base.day13;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction throws处理异常
*
* 为什么要有throws处理方式?
* 我们通过try...catch可以对异常进行处理了,但是并不是所有的时候我们都有权限进行异常的处理。
* 也就是说,有些时候我们处理不了,但是,这个时候异常时存在的,不处理也不行,怎么办?
* 这个时候,Java就提供了throws的处理方案。
*
* throws使用的格式&注意事项?
* 格式:
* throws 异常类名
* 注意:这个格式必须跟在方法的括号的后面
*
* 注意:
* 编译时异常时必须要进行处理的,两种处理方案:try...catch...或者throws
* 如果你采用了throws这种方案,将来谁调用,还得进行处理。
*
* 运行时异常可以不用处理,出现问题后我们需要回来修改代码。
*/
public class Demo3Throws {
public static void main(String[] args) {
System.out.println("程序开始执行");
try {
/*
java.text.ParseException: Unparseable date: "abc"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.groupies.base.day13.Demo3Throws.method(Demo3Throws.java:55)
at com.groupies.base.day13.Demo3Throws.main(Demo3Throws.java:38)
*/
method();//【报错定位】第38行
} catch (ParseException e) {
e.printStackTrace();
}
/*
Exception in thread "main" java.lang.ArithmeticException: / by zero
at com.groupies.base.day13.Demo3Throws.method2(Demo3Throws.java:63)
at com.groupies.base.day13.Demo3Throws.main(Demo3Throws.java:47)
*/
method2();
System.out.println("程序结束执行");
}
//编译时异常 注意导包 import java.text.ParseException;
public static void method() throws ParseException {
String s = "abc";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d = sdf.parse(s);//【报错位置】第55行
System.out.println(d);
}
//运行时异常
public static void method2() throws ArithmeticException {
int a = 10;
int b = 0;
System.out.println(a / b);//【报错定位】第63行
}
}
2 File类
2.1 File类的概述
- File :文件和目录路径名的抽象表示形式
- 也就是说文件和目录(文件夹)是可以通过File封装成对象的
- File类的构造方法
//a. 通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。 File(String pathname) //b. 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。 File(String parent, String child) //c. 根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实 File(File parent, String child)
案例代码四 File类的构造方法
package com.groupies.base.day13;
import java.io.File;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction File类的构造方法
*
* file构造方法:
* a. File(String pathname):通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。
* b. File(String parent, String child):根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
* c. File(File parent, String child):根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实
*
*/
public class Demo4File {
public static void main(String[] args) {
//以下的f1,f2,f3做的是同样的事情,就是把d:\\aa\\b.txt转换为了一个File对象
//a. File(String pathname)
File f1 = new File("d:\\aa\\b.txt");
//b. File(String parent, String child)
File f2 = new File("d:\\aa", "b.txt");
//c. File(File parent, String child)
File f3_path = new File("d:\\aa");
File f3 = new File(f3_path, "b.txt");
}
}
2.2 File类的方法
2.2.1 创建
- 方法摘要
//a.创建文件 如果文件不存在,创建文件并返回true 如果文件存在,创建文件失败并返回false public boolean createNewFile(): //b.创建目录 如果目录不存在,创建目录并返回true 如果目录存在,创建目录失败并返回false public boolean mkdir() //c.创建多级目录 public boolean mkdirs()
案例代码五 File类方法–创建
package com.groupies.base.day13;
import java.io.File;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction File类方法--创建
*
* 创建功能
* a. File.createNewFile():创建文件
* 如果文件不存在,创建文件并返回true
* 如果文件存在,创建文件失败并返回false
* b. File.mkdir():创建目录
* 如果目录不存在,创建目录并返回true
* 如果目录存在,创建目录失败并返回false
* c. File.mkdirs():创建多级目录
*
* File.separator
* 其实File.separator 的作用相当于 '\'
* 在 windows 中文件文件分隔符 用 '\' 或者'/' 都可以
* 但是在 Linux 中,是不识别 '\'的,而File.separator 是系统默认的文件分隔符号,在 UNIX 系统上,此字段的值为'/'
* 在Microsoft Windows 系统上,它为 '\'屏蔽了这些系统的区别。
* 所以用 File.separator 保证了在任何系统下不会出错。
*
* 需求:
* 1:【createNewFile】 在d盘目录下创建一个文件a.txt
* 2:【mkdir】 在d盘目录下创建一个目录bb
* 3:【mkdirs】 在d盘目录下创建一个多级目录cc\\dd
* 4:【mkdir + createNewFile】 在d盘目录下创建一个文件ee\\f.txt
*/
public class Demo5FileMethodCreate {
public static void main(String[] args) {
//需求1:我要在d盘目录下创建一个文件a.txt
File f1 = new File("D:\\a.txt");//1.createNewFile:true
try {
System.out.println("1.createNewFile:" + f1.createNewFile());
} catch (IOException e) {
System.out.println("IO异常,创建失败");
}
//需求2:我要在d盘目录下创建一个目录bb
File f2 = new File("D:" + File.separator + "bb");
System.out.println("2.mkdirs:" + f2.mkdirs());//2.mkdirs:true
//需求3:我要在d盘目录下创建一个多级目录cc\\dd
File f3 = new File("D:\\cc" + File.separator + "dd");
System.out.println("3.mkdirs:" + f3.mkdirs());//3.mkdirs:true
//需求4:我要在d盘目录下创建一个文件ee\\f.txt
File f4_path = new File("D:\\ee");
File f4_file = new File(f4_path, "f.txt");
System.out.println("4.mkdir:" + f4_path.mkdirs());//5.mkdir:true
try {
System.out.println("4.createNewFile:" + f4_file.createNewFile());//5.createNewFile:true
} catch (IOException e) {
System.out.println("IO异常,创建失败");
}
}
}
2.2.2 删除
- 相对路径&绝对路径
- 绝对路径:是以盘符开始的路径。d:\aa\b.txt
- 相对路径:不以盘符开始。相对于当前的项目而言,在项目的目录下。如何显示出来呢?刷新项目就可以了。
- 方法摘要
public boolean delete():删除文件和目录
- 注意事项
- 如果一个目录中有内容(目录,文件),就不能直接删除。
- 应该先删除目录中的内容,最后才能删除目录。
案例代码六 File类方法–删除
package com.groupies.base.day13;
import java.io.File;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction File类方法--删除
*
* 相对路径&绝对路径
* 绝对路径:是以盘符开始的路径。d:\\aa\\b.txt
* 相对路径:不以盘符开始。相对于当前的项目而言,在项目的目录下(与src同级目录)。如何显示出来呢?刷新项目就可以了。
*
* 方法摘要&注意事项
* 删除功能
* public boolean delete():删除文件和目录
*
* 注意:
* 如果一个目录中有内容(目录,文件),就不能直接删除。
* 应该先删除目录中的内容,最后才能删除目录。
*
* 需求:
* 1. createNewFile:相对路径创建一个文件a.txt
* 2. mkdir+createNewFile:相对路径创建一个文件cc\\d.txt
* 3. getAbsolutePath:获取项目根目录路径
* 4. delete:相对路径删除a.txt这个文件
* 5. delete: 相对路径删除cc这个目录(先删除d.txt这个文件,再删除cc这个目录)
*/
public class Demo6FileMethodDelete {
public static void main(String[] args) throws InterruptedException, IOException {
//需求1. createNewFile:相对路径创建一个文件a.txt.
File f1 = new File("a.txt");
System.out.println("1.创建一个文件a.txt: " + f1.createNewFile());
//需求2. mkdir+createNewFile:相对路径创建一个文件cc\\d.txt
File f2_path = new File("cc");
File f2_file = new File("cc" + File.separator + "a.txt");
System.out.println("3.创建一个目录cc: " + f2_path.mkdirs());
System.out.println("3.创建一个文件cc\\d.txt: " + f2_file.createNewFile());
//等待10秒
File projectPath = new File("");//参数为空,表示当前项目根目录
System.out.println("全部创建完毕,请进入 " + projectPath.getAbsolutePath() + " 目录查看文件,15秒后开始删除");
Thread.sleep(15000);//线程等待15秒
//需求4.delete:相对路径删除a.txt这个文件
File f4 = new File("a.txt");
System.out.println("删除a.txt: " + f4.delete());
//需求5. delete: 相对路径删除cc这个目录(先删除d.txt这个文件,再删除cc这个目录)
File f5_file = new File("cc" + File.separator + "a.txt");
File f5_path = new File("cc");
System.out.println("删除cc\\a.txt文件: " + f5_file.delete());
System.out.println("删除cc目录: " + f5_path.delete());
}
}
- 遍历File目录,删除所有目录下文件
/**
* @introduction 遍历File目录,删除所有文件
* @param f
*/
public static void deleteFile(File f) {//传一个File对象f进去 因为要调用其方法
if (f != null) {//判断f数据是否为空 因为可能有人会传null值进来
if (f.exists()) {//判断该抽象路径的目录和文件是否存在
if (f.isDirectory()) {//判断是否是目录
File[] listFiles = f.listFiles();//调用listFiles()方法返回一个File对象组成的数组集合
if (listFiles == null) {//如果该数组为Null说明没有文件和目录对象 就是一个空的文件夹
f.delete();//直接删除
} else {//不为空的文件夹
for (File file : listFiles) {//遍历该集合
deleteFile(file);//遍历到的每个File对象传入demo()方法
}
f.delete();//最后将这个不为空的文件夹删除
}
} else {//不是目录可能是是文件或者不存在
f.delete();//直接删除
}
} else {//为Null
return;//结束方法调用
}
}
}
2.2.3 判断&获取
- 方法摘要
/******a.判断功能******/ //a1.判断是否是目录 public boolean isDirectory() //a2.判断是否是文件 public boolean isFile() //a3.判断是否存在 public boolean exists() /******b.获取功能******/ //b1.获取绝对路径 public String getAbsolutePath() //b2.获取相对路径 public String getPath() //b3.获取名称 public String getName()
案例代码七 File类方法–判断、获取
package com.groupies.base.day13;
import java.io.File;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction File类方法--判断、获取
*
* 判断功能
* a. File.isDirectory():判断是否是目录
* b. File.isFile():判断是否是文件
* c. File.exists():判断是否存在
* 获取功能
* d. File.getAbsolutePath():获取绝对路径
* e. File.getPath():获取相对路径
* f. File.getName():获取名称
*/
public class Demo7FileMethodJudgeGet {
public static void main(String[] args) {
//创建File对象
File f = new File("aaa" + File.separator + "bbb.txt");
//判断功能
System.out.println("-----a. File.isDirectory():判断是否是目录-----");
System.out.println(f.isDirectory());//false
System.out.println("-----b. File.isFile():判断是否是文件-----");
System.out.println(f.isFile());//false
System.out.println("-----c. File.exists():判断是否存在-----");
System.out.println(f.exists());//false
System.out.println("-----d. File.getAbsolutePath():获取绝对路径-----");
System.out.println(f.getAbsolutePath());//F:\Data_bak\java\base\aaa\bbb.txt
System.out.println("-----e. File.getPath():获取相对路径-----");
System.out.println(f.getPath());//aaa\bbb.txt
System.out.println("-----f. File.getName():获取名称-----");
System.out.println(f.getName());//bbb.txt
}
}
3 IO流
- 什么是IO流,其作用为?
- I ------ Input --> 输入 --> 读取
- O — Output --> 输出 --> 写出
- 常见应用
- 文件复制
- 文件上传
- 文件下载
IO流的分类汇总
- 按类型分类
- a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
- b. 字节缓冲区流 (字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码)
- c. 转换流 (字符流) = 字节流 + 编码表
- d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
- e. 字符缓冲区流
- a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
- a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
- InputStream 字节流输入超类
- FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- b. 字节缓冲区流 BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
- FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- OutPutStream 字节流输出超类
- FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- b 字节缓冲区流 BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码
- FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- InputStream 字节流输入超类
- c. 转换流 (字符流) = 字节流 + 编码表
- d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
- Reader 字符流输入超类
- InputStreamReader 用 默认/指定 编码读数据
- FileReader ↓作为BufferedReader构造器的参数使用↓
- e. 字符缓冲区流 BufferedReader 最常用
- Writer 字符流输出超类
- PrintWriter
- OutputStreamWriter 用 默认/指定 编码写数据
- FileWriter ↓作为BufferedWriter构造器的参数使用↓
- e. 字符缓冲区流 BufferedWriter 最常用
- IO流的分类 throws FileNotFoundException
- 按类型分类
- a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
- a1 InputStream 字节流输入超类
- a1.1 FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
//指定输入流 //FileInputStream fis = new FileInputStream(new File("fis.txt"));//效果同下行代码 FileInputStream fis = new FileInputStream("fis.txt"); //a.一次读取一个字符 int by; //如果fis.read不等于-1说明还有数据,则继续读文件 while ((by = fis.read()) != -1) { System.out.print((char) by);//打印结果 } //b.一次读取一个字符数组 byte[] bys = new byte[1024];//每次读取最大bys长度个字节存入数组,长度建议1024或1024的整数倍 int len;//代表有效个数 //将数据读取到数组中, 并用len记录读取到的有效字节个数 //fis.read(bys)=>读取一次bys长度内容写入bys(每次覆盖之前内容),如果剩余文件内容不足以写满bys,(长度1024,剩余1000字节)则bys中最后字节(24字节)保持上一次写入的内容 => 所以每次要截取new String(bys,0,len),避免读到上一次剩余的内容 while ((len = fis.read(bys)) != -1) { System.out.print(new String(bys, 0, len));//打印结果 } //释放资源 fis.close();
- b1. 字节缓冲区流 BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
//字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流 //Q:为什么字节缓冲流的构造方法需要传入一个In/OutputStream //A:字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。 //指定输入流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("name.txt")); //a.一次读取一个字符(不能读取中文,中文一般2-4字节,一个一个字节读会乱码) int by; while ((by = bis.read()) != -1) { System.out.print((char) by); } //b.一次读取一个字符数组 byte[] bys = new byte[1024]; int len; while ((len = bis.read(bys)) != -1) { System.out.print(new String(bys, 0, len)); } //释放资源 bis.close();
- b1. 字节缓冲区流 BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
- a1.1 FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- a2 OutPutStream 字节流输出超类
- a2.1 FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
//指定输出流 //FileOutputStream fos = new FileOutputStream(new File("fos.txt"));//效果同下行代码 //FileOutputStream fos = new FileOutputStream("fos.txt" , false);//false表示不追加文件->每次写入覆盖之前的内容 FileOutputStream fos = new FileOutputStream("fos.txt"); FileInputStream fis = new FileInputStream("fis.txt"); //a.一次写入一个字符(不能读取中文,中文一般2-4字节,一个一个字节读会乱码) int by; while ((by = fis.read()) != -1) { System.out.print((char) by);//打印结果 } //b.一次写入一个字符数组 byte[] bytes = new byte[1024]; int len; while ((len = fis.read(bytes)) != -1) { fos.write(bytes, 0, len); } //释放资源 fos.close(); fis.close();
- b2. 字节缓冲区流 BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码
//字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流 //Q:为什么字节缓冲流的构造方法需要传入一个In/OutputStream //A:字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。 //指定输入流 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt")); //a.一次读取一个字符 int by; while ((by = bis.read()) != -1) { bos.write(by);//写入字符串 bos.flush();//刷新该流的缓冲,写入文件 } //b.一次读取一个字符数组 byte[] bytes = new byte[1024]; int len; while ((len = bis.read(bytes)) != -1) { System.out.println(new String(bytes,0,len)); bos.write(bytes,0,len);//写入字符串 bos.flush();//刷新该流的缓冲,写入文件 } //释放资源 bis.close(); bos.close();
- b2. 字节缓冲区流 BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码
- a2.1 FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- a1 InputStream 字节流输入超类
- c. 转换流 (字符流) = 字节流 + 编码表
//指定编码为UTF-8的字符输出流 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("source.txt"),"UTF-8"); //指定编码为UTF-8的字符输入流 InputStreamReader isr = new InputStreamReader(new FileInputStream("target.txt"),"UTF-8"); /* 常见的编码表: ASCII : 美国标准信息交换码, 用一个字节的7位表示数据 ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII GB2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII UTF-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, 兼容ASCII用在网页上可以 统一页面中的中文简体繁体和其他语言的显示. */
- d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
- d1 Reader 字符流输入超类
- d1.1 InputStreamReader 用 默认/指定 编码读数据
//指定输入流 目标文件和字符集 ,如果不指定字符集则按照默认编码表 (java7=GBK,java8=UTF-8) InputStreamReader isr = new InputStreamReader(new FileInputStream(""),"GBK");
- d1.1.1 FileReader ↓作为BufferedReader构造器的参数使用↓
//转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流InputStreamReader提供了对应的子类InputStreamReader /* (子类)FileWriter:用来写入字符文件的便捷类 (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8) (子类)FileReader:用来读取字符文件的便捷类 (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8) */ //封装数据源 FileReader fr = new FileReader("source.txt"); //封装目的地 FileWriter fw = new FileWriter("target.txt");
- d1.1.1 FileReader ↓作为BufferedReader构造器的参数使用↓
- e1. 字符缓冲区流 BufferedReader 最常用
//指定输入流 BufferedReader br = new BufferedReader(new FileReader("source.txt")); //指定输出流 BufferedWriter bw = new BufferedWriter(new FileWriter("target.txt")); //a.一次读取一个字符 int ch; while ((ch = br.read()) != -1) { //对应Unicode编码10进制的值 查询工具 => //http://www.mytju.com/classcode/tools/encode_gb2312.asp System.out.println(ch); } //b.一次读取多个字符【注意 换行符也算字符】 char[] bytes = new char[1024];//一次取出1024个字符 int len;//代表有效个数 while((len = br.read(bytes)) != -1) { System.out.print(new String(chars, 0, len));//注意是print不是println } //c.读取一整行字符串【注意 不包括换行符,需要手动newLine()换行】 //String line = br.readLine(); String line;//代表一整行字符串 //按行读取整篇文章的内容 while((line = br.readLine()) != null) { System.out.println(line); } //释放资源 br.close(); bw.close();
- d1.1 InputStreamReader 用 默认/指定 编码读数据
- d2 Writer 字符流输出超类
- d2.1 PrintWriter
- d2.2 OutputStreamWriter 用 默认/指定 编码写数据
//指定输出流 目标文件和字符集,如果不指定字符集则按照默认编码表 (java7=GBK,java8=UTF-8) OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("target.txt"),"GBK");
- d2.2.1 FileWriter ↓作为BufferedWriter构造器的参数使用↓
//转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流OutputStreamWriter提供了对应的子类FileWriter /* (子类)FileWriter:用来写入字符文件的便捷类 (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8) (子类)FileReader:用来读取字符文件的便捷类 (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8) */ //封装数据源 FileReader fr = new FileReader("source.txt"); //封装目的地 FileWriter fw = new FileWriter("target.txt");
- d2.2.1 FileWriter ↓作为BufferedWriter构造器的参数使用↓
- e2. 字符缓冲区流 BufferedWriter 最常用
//指定输入流 BufferedReader br = new BufferedReader(new FileReader("br.txt")); //指定输出流 BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")); //a.一次读取一个字符 int ch; while ((ch = br.read()) != -1) { bw.write(ch);//写入字符串 bw.flush();//刷新该流的缓冲,写入文件 } //b.一次读取多个字符【注意 换行符也算字符】 char[] bytes = new char[1024];//一次取出1024个字符 int len;//代表有效个数 while((len = br.read(bytes)) != -1) { bw.write(new String(bytes, 0 , len));//写入字符串 bw.newLine(); bw.flush();//刷新该流的缓冲,写入文件 } //c.读取一整行字符串【注意 不包括换行符,需要手动newLine()换行】 //String line = br.readLine(); String line;//代表一整行字符串 //按行读取整篇文章的内容 while((line = br.readLine()) != null) { bw.write(line);//写入字符串 bw.newLine(); bw.flush();//刷新该流的缓冲,写入文件 } //释放资源 br.close(); bw.close();
- d1 Reader 字符流输入超类
- a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
- 按流向分类
- 输入流 : 用来读取数据的
- 输出流 : 用来写出数据的
- 按类型分类
3.1 字节流
a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
- InputStream 字节流输入超类
- FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- b. 字节缓冲区流 BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
- OutPutStream 字节流输出超类
- FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- b 字节缓冲区流 BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码
- FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
3.1.1 FOS与FIS
- 简写说明
- FIS = FileInPutStream
- FOS = FileOutPutStream
- 字节流写数据
- OutputStream:此抽象类是表示输出字节流的所有类的超类
- FileOutputStream:文件输出流是用于将数据写入 File
- 字符流读数据
- OutputStream:此抽象类是表示输出字节流的所有类的超类
- FileOutputStream:文件输出流是用于将数据写入 File
- 构造方法
//创建一个向具有指定名称的文件中写入数据的输出文件流。 FileOutputStream(String name)
- 字节流写数据的步骤
- A:创建字节输出流对象
- B:调用写数据的方法 write(int);
- C:释放资源 close()
案例代码八 字节流FileOutputStream写出数据
package com.groupies.base.day13;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction 字节流FileOutputStream写出数据
*
* 字节流:
* InputStream 字节输入流
* OutputStream 字节输出流
* 字符流:
* Reader 字符输入流
* Writer 字符输出流
*
* 字节流写数据
* OutputStream:此抽象类是表示输出字节流的所有类的超类
* FileOutputStream:文件输出流是用于将数据写入 File
*
* 构造方法:
* FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。
*
* 字节流写数据的步骤:
* A:创建字节输出流对象
* B:调用写数据的方法
* C:释放资源
*/
public class Demo8FileOutputStream {
public static void main(String[] args) throws IOException {
//创建字节输出流对象 throws FileNotFoundException
FileOutputStream fos = new FileOutputStream("a.txt");
/*
创建字节输出流对象做了3件事
a. 调用File类创建了文件
b. 创建字节输出流对象
c. 让fos这个对象指向a.txt这个文件
*/
//throws IOException (包含FileNotFoundException)
System.out.println("fos.write");
//FileOutputStream.write(int b); b = 十进制的unicode编码
fos.write(65);//A
fos.write(66);//B
System.out.println("写入结束");
//关闭IO流,回收系统资源
fos.close();
}
}
3.1.2 FOS写数据的三种方式
- 方法摘要
//a.写出数据的三个方法 //一次写一个字节 public void write(int b) //一次写一个字节数组 public void write(byte[] b) //一次写一个字节数组的一部分 public void write(byte[] b,int off,int len) //b.String类中的方法 //将字符串转换为字节数组 byte[] getBytes()
案例代码九 字节流FileOutputStream写数据的三种方式
package com.groupies.base.day13;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction 字节流FileOutputStream写数据的三种方式
*
* A.构造方法的三种方式:
* 1. FileOutputStream(String name)
* 2. FileOutPutStream(File file)
* 3. FileOutPutStream(new File(xxx))
* 4. FileOutputStream(xxx,true) //true=追加数据,默认为false,清空后重新写入数据
*
* B.写数据的三种方式: throws IOException
* 1. FileOutputStream.write(int b):一次写一个字节
* 2. FileOutputStream.write(byte[] b):一次写一个字节数组
* 3. FileOutputStream.write(byte[] b,inf off,int len):一次写一个字节数组的一部分
*
* 字节流写数据的步骤:
* a: 创建字节输出流对象 new FileOutPutStream(String name)
* b: 调用写数据的方法
* c: 释放资源 fos.close()
*/
public class Demo9FileOutPutStreamMethod {
public static void main(String[] args) throws IOException {
//A1. FileOutputStream构造方式1 FileOutputStream(String name)
FileOutputStream fos1 = new FileOutputStream("b.txt");
//A2. FileOutputStream构造方式2 FileOutPutStream(File file)
File f2 = new File("c.txt");
FileOutputStream fos2 = new FileOutputStream(f2);
//A3. FileOutPutStream构造方式3 FileOutPutStream(new File(xxx))
FileOutputStream fos3 = new FileOutputStream(new File("d.txt"));
//B1. 写入数据方式1 FileOutputStream.write(int b):一次写一个字节
//throws IOException
fos1.write(65);
//B2. 写入数据方式2 FileOutputStream.write(byte[] b):一次写一个字节数组
byte[] bys = {65, 66, 67, 68, 69};
fos2.write(bys);
//B3. 写入数据方式3 FileOutputStream.write(byte[] b,inf off,int len):一次写一个字节数组的一部分
fos3.write("ABCDE".getBytes(), 0, 3);
File path = new File("");
System.out.println("文件路径:" + path.getAbsolutePath());
//释放资源
fos1.close();
fos2.close();
fos3.close();
}
}
3.1.3 FOS如何实现换行和追加写数据
FIS = FileInPutStream
- 不同的操作系统,针对换行的符号识别是不一样的。
- windows:\r\n
- linux:\n
- mac:\r
- 如何实现数据的追加写入?
- 用构造方法带第二个参数是true的情况即可
案例代码十 字节流FileOutputStream写数据换行、追加
package com.groupies.base.day13;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction 字节流FileOutputStream写数据换行、追加
*/
public class Demo10FileOutPutStreamNewLine {
public static void main(String[] args) throws IOException {
//先清空文件
FileOutputStream clear = new FileOutputStream("b.txt");
clear.write("".getBytes());
//如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处(默认为false)
FileOutputStream fos = new FileOutputStream("b.txt", true);
//循环写入三次hello和换行
for (int i = 0; i < 3; i++) {
fos.write("hello".getBytes());
fos.write("\r\n".getBytes());
}
System.out.println("文件路径为:" + new File("").getAbsolutePath());
//释放资源
fos.close();
}
}
3.1.4 FOS写数据加入异常处理
FIS = FileInPutStream
- try…catch.finally
//格式 try{ 可能发生问题的代码 }catch(){ 处理异常代码 }finally{ 一定会被执行的代码. // 通常用于释放资源, 做善后的动作 }
案例代码十一 字节流FileOutputStream写数据加入异常处理
package com.groupies.base.day13;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction 字节流FileOutputStream写数据加入异常处理
*
* 格式:
* try{
* 可能发生问题的代码
* }catch(){
* 处理异常代码
* }finally{
* 一定会被执行的代码. // 通常用于释放资源, 做善后的动作
* }
*/
public class Demo11FOSTryCatch {
public static void main(String[] args) {
//fos放在外面是为了在finally中可以关闭
FileOutputStream fos = null;
try {
fos = new FileOutputStream("d.txt");
fos.write("hello".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
//释放资源
try {
fos.close();
} catch (IOException e) {
System.out.println("fos关闭失败");
}
}
}
}
}
3.1.5 FIS读数据方式1一次读取一个字节
FIS = FileInPutStream
- 字节流读数据的步骤
- A : 创建字节输入流对象
- B : 调用读数据的方法
- C : 释放资源
案例代码十二 字节流FileInputStream读数据方式1
package com.groupies.base.day13;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction 字节流FileInputStream读数据方式1
*
* 读数据方式1: 一次读取一个字节
* int by;
* while((by=fis.read())!=-1) {
* System.out.print((char)by);
* }
*
* 读数据方式2: 一次读取一个字节数组
* //数组长度为1024或者1024的整数倍
* byte[] bys = new byte[1024];
* int len;
* //将数据读取到数组中, 并用len记录读取到的有效字节个数
* while((len=fis.read(bys))!=-1) {
* //byte --> String new String(bys,0,len)
* System.out.print(new String(bys,0,len));
* }
*/
public class Demo12FileInputStreamType1 {
public static void main(String[] args) throws IOException {
System.out.println("读数据方式1: 一次读取一个字节");
//创建字节输入流对象
FileInputStream fis1 = new FileInputStream("b.txt");//刚才在b.txt写入了3行hello
for (int i = 0; i < 200; i++) {
/*
104 => h
101 => e
108 => l
108 => l
111 => o
13 => \r
10 => \n
...
-1 => 没有数据
-1 => 没有数据
-1 => 没有数据
...
*/
System.out.println(fis1.read());
}
System.out.println("改进为循环方式打印");
FileInputStream fis2 = new FileInputStream("b.txt");//刚才在b.txt写入了10行helloWorld
int by;
//如果fis.read不等于-1说明还有数据,则继续读文件
while ((by = fis2.read()) != -1) {
/*
hello
hello
hello
hello
hello
hello
hello
hello
hello
hello
*/
System.out.print((char) by);
}
}
}
3.1.6 FIS读数据方式2一次读取一个字节数组
- 方法摘要
/*从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中 返回值是读入缓冲区的字节总数,也就是实际的读取个数 如果因为已经到达文件末尾而没有更多的数据,则返回 -1。*/ public int read(byte[] b):
案例代码十三 字节流FileInputStream读数据方式2
package com.groupies.base.day13;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/23
* @introduction FileInputStream读数据方式2
*
* public int read(byte[] b):
* 从次输入流中将最多b.length 个字节的数据读入一个byte数组中
* 返回值是读入缓冲区的字节总数
*
* 读数据方式1: 一次读取一个字节
* int by;
* while((by=fis.read())!=-1) {
* System.out.print((char)by);
* }
* byte -> String 通过构造方法转换
* String(byte[] bytes)
* String(byte[] bytes,int offset,int length) offset 开始位置;length 截取长度
*
* byte数组长度为1024或者1024的整数倍:
* 1G=1024MB
* 1MB=1024KB
*
* 读数据方式2: 一次读取一个字节数组
* //数组长度为1024或者1024的整数倍
* byte[] bys = new byte[1024];
* int len;
* //将数据读取到数组中, 并用len记录读取到的有效字节个数
* while((len=fis.read(bys))!=-1) {
* //byte --> String new String(bys,0,len)
* System.out.print(new String(bys,0,len));
* }
*/
public class Demo13FileInputStreamType2 {
public static void main(String[] args) throws IOException {
System.out.println("-----读数据方式2: 一次读取一个字节数组-----");
FileInputStream fis1 = new FileInputStream("b.txt");//刚才在b.txt写入了3行hello
//标准代码字符缓冲区bys1长度应为1024或1024的整数倍,这里先用8演示读取的原理
byte[] bys1 = new byte[8];
//第一次读取
int len1 = fis1.read(bys1);
System.out.println(len1);//8
/*
第一次读取: hello
h
*/
System.out.println("第一次读取: " + new String(bys1));
//第二次读取
len1 = fis1.read(bys1);
System.out.println(len1);//8
/*
第二次读取: ello
he
*/
System.out.println("第二次读取: " + new String(bys1));
//第三次读取
len1 = fis1.read(bys1);
System.out.println(len1);//5 => 只读取了5个字符,就返回了5
/*
第三次读取: llo
he
*/
/* 解析:
文件内容为
hello\r\n
hello\r\n
hello\r\n
第一次读取8个字节为 [h] [e] [l] [l] [o] [\r][\n] [h]
第二次读取8个字节为 [e] [l] [l] [o] [\r][\n] [h] [e]
第三次读取8个字节为 [l] [l] [o] [\r][\n]
但数组写入方式是每次覆盖前一次的,所以第二次写入的还保留着
bys[5] = \r
bys[6] = h
bys[7] = e
所以第三次数组内容为 [l] [l] [o] [\r][\n][\n] [h] [e]
所以才会打印出以上内容
*/
System.out.println("第三次读取: " + new String(bys1));
//第四次读取
len1 = fis1.read(bys1);
System.out.println(len1);//-1 => 表示没有数据了
System.out.println("-----改进为循环读取文件-----");
//创建字节输入流对象
FileInputStream fis2 = new FileInputStream("b.txt");
byte[] bys2 = new byte[1024]; //1024或者1024的整数倍
int len2;
//将数据读取到数组中, 并用len记录读取到的有效字节个数
while ((len2 = fis2.read(bys2)) != -1) {
//只读取到len的长度,否则会出现
System.out.print(new String(bys2, 0, len2));
}
System.out.println("\r\n读取结束");
fis2.close();
}
}
3.1.7 字节流练习之复制文本文件
- 需求
- 拷贝文本文件
- 分析
- 第一步: 创建输入输出流对象关联数据源和数据目的
- 第二步: 定义字节数组,为了提高效率
- 第三步: 将数据通过while循环不断读取到字节数组中
- 第四步: 将数据从字节数组中取出并写出
- 第五步: 释放资源
- 待拷贝的文本文件(d:\窗里窗外.txt)
《窗里窗外》是林青霞近5年所写的46篇散文的结集,虽是旧作,但该书记录她19岁以《窗外》成名后多方面的人生经历,字字真实深刻。《窗里窗外》共分为六个章节:“戏”里说的是她的出道故事、拍戏的甘苦、对于作品的内心话;“亲”谈她的家人亲情;“友”则书写她与挚友的交往,细谈她与三毛、黄霑、张国荣、龙应台、琼瑶、徐克等人的往来互动;“趣”是她的生活记趣,有旅行见闻,也有她与影迷的邂逅;“缘”则书写她一生难忘的相遇,像是和记者的友谊,和季羡林的会面之缘;“悟”里记录了她对人生的体悟和感动,以及她向圣严法师求道的故事。此外,书中还完整收录了林青霞一些未公开的照片。
第1节:人生小语(1)…
案例代码十四 字节流练习之复制文本文件
package com.groupies.base.day13;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/25
* @introduction 字节流练习之复制文本文件
*
* 需求:
* 拷贝文本文件
* 分析:
* 第一步: 创建输入输出流对象关联数据源和数据目的
* 第二步: 定义字节数组,为了提高效率
* 第三步: 将数据通过while循环不断读取到字节数组中
* 第四步: 将数据从字节数组中取出并写出
* 第五步: 释放资源
*/
public class Demo14FileCopy {
public static void main(String[] args) throws IOException {
//封装数据源
FileInputStream fis = new FileInputStream("d:" + File.separator + "窗里窗外.txt");
//封装目的地(目标文件,追加true清空重写false)
FileOutputStream fos = new FileOutputStream("d:" + File.separator + "林青霞.txt", false);
//a.一次写入一个字符
int by;
while ((by = fis.read()) != -1) {
fos.write(by);
}
//b.一次写入一个字符数组
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
//释放资源
fos.close();
fis.close();
}
}
3.2.8 字节流练习之复制图片
- 思路
- 同理3.1.7案例
案例代码十五 字节流练习之复制图片
package com.groupies.base.day13;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* @author GroupiesM
* @date 2021/04/25
* @introduction 字节流练习之复制图片
*/
public class Demo15PictureCopy {
public static void main(String[] args) throws IOException {
//封装数据源
FileInputStream fis1 = new FileInputStream("d:" + File.separator + "01_字节流体系图.jpg");
FileInputStream fis2 = new FileInputStream("d:" + File.separator + "01_字节流体系图.jpg");
//封装目的地
FileOutputStream fos1 = new FileOutputStream("d:" + File.separator + "copy1.jpg");
FileOutputStream fos2 = new FileOutputStream("d:" + File.separator + "copy2.jpg");
//读写数据
int by;
//方式1:一次读取一个字节
//如果fis.read不等于-1说明还有数据,则继续读文件
while ((by = fis1.read()) != -1) {
fos1.write(by);
}
//方式2:一次读取一个字节数组
byte[] bys = new byte[1024];
int len;
while ((len = fis2.read(bys)) != -1) {
fos2.write(bys, 0, len);
}
//释放资源
fis1.close();
fis2.close();
fos1.close();
fos2.close();
}
}
3.2 字节缓冲区流
a.字节流 (支持图片等格式的文件,直接用记事本打开文件是看不懂的乱码)
- InputStream 字节流输入超类
- FileInputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- b. 字节缓冲区流 BufferedInputStream 字符缓冲输入流 b、c方式 可以读取中文,不会出现乱码
- OutPutStream 字节流输出超类
- FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
- b 字节缓冲区流 BufferedOutputStream 字节缓冲输出流 可以读取中文,不会出现乱码
- FileOutputStream 不建议读取中文,中文一般2-4字节,此方式会从中间截断,导致乱码
3.2.1 概述
- 作用
- 字节流一次读写一个数组的速度比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果
- java本身在设计的时候,也考虑到了这样的设计思想,所以提供了字节缓冲区流
- 字节缓冲流
- BufferedOutputStream : 字节缓冲输出流
- BufferedInputStream : 字节缓冲输入流
- 为什么字节缓冲流的构造方法需要传入一个OutputStream
- 字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作
案例代码十六 字节缓冲流概述
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/04/27
* @introduction 字节缓冲流
*
* 构造方法
* BufferedOutputStream(OutputStream out)
* BufferedInputStream(InputStream in)
*
* 方法摘要
* BufferedOutputStream.write(byte b[])
*/
public class Demo16BufferedOutputStream {
public static void main(String[] args) throws IOException {
//指定字符缓冲输出流
// FileOutputStream fos = new FileOutputStream("a.txt");
// BufferedOutputStream bos = new BufferedOutputStream(fos);
// 上面的两句等价于下面的这一句
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("a.txt"));
byte[] bytes = "hello".getBytes();
bos.write(bytes);//写入字符数组
bos.close();
//指定字符缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
//方式1 : 一次读取一个字节
int by;
while ((by = bis.read()) != -1) {
System.out.println((char) (by));
}
//方式2 : 一次读取一个字节数组
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys)) != -1) {
System.out.println(new String(bys, 0, len));
}
//释放资源
bos.close();
bis.close();
}
}
3.2.2 四种方式复制图片效率测试
-
方法摘要
//返回以毫秒为单位的当前时间。 public static long currentTimeMillis()
案例代码十七 字节流&字节缓冲区流四种方式复制AVI并测试效率
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/04/27
* @introduction 字节流&字节缓冲区流四种方式复制AVI并测试效率
*
* 源文件: d:\\复制视频.avi
* 大小: 34904KB
*
* method1: 基本字节流,一次读取一个字节 => method1.avi => 198001毫秒
* method2: 基本字节流,一次读写一个字节数组 => method2.avi => 278毫秒
* method3: 缓冲字节流,一次读取一个字节 => method3.avi => 384毫秒
* method4: 缓冲字节流,一次读写一个字节数组 => method4.avi => 190毫秒
*
* 结论: method4 > method2 > method3 > method1
*/
public class Demo17BufferedOutputStreamCopyAVITest {
public static void main(String[] args) throws IOException {
//记录method1时间
long start1 = System.currentTimeMillis();
method1();//method1共耗时198001毫秒
long end1 = System.currentTimeMillis();
System.out.println("method1共耗时" + (end1 - start1) + "毫秒");
//记录method2时间
long start2 = System.currentTimeMillis();
method2();//method2共耗时278毫秒
long end2 = System.currentTimeMillis();
System.out.println("method2共耗时" + (end2 - start2) + "毫秒");
//记录method3时间
long start3 = System.currentTimeMillis();
method3();//method3共耗时384毫秒
long end3 = System.currentTimeMillis();
System.out.println("method3共耗时" + (end3 - start3) + "毫秒");
//记录method4时间
long start4 = System.currentTimeMillis();
method4();//method4共耗时190毫秒
long end4 = System.currentTimeMillis();
System.out.println("method4共耗时" + (end4 - start4) + "毫秒");
}
//method1: 基本字节流,一次读取一个字节 => method1.avi
private static void method1() throws IOException {
//封装数据源
FileInputStream fis = new FileInputStream("d:\\复制视频.avi");
//封装目的地
FileOutputStream fos = new FileOutputStream("d:\\method1.avi");
int by;
while ((by = fis.read()) != -1) {
fos.write(by);
}
//释放资源
fis.close();
fos.close();
}
//method2: 基本字节流,一次读写一个字节数组 => method2.avi
private static void method2() throws IOException {
//封装数据源
FileInputStream fis = new FileInputStream("d:\\复制视频.avi");
//封装目的地
FileOutputStream fos = new FileOutputStream("d:\\method2.avi");
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
//释放资源
fis.close();
fos.close();
}
//method3: 缓冲字节流,一次读取一个字节 => method3.avi
private static void method3() throws IOException {
//封装数据源
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制视频.avi"));
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\method3.avi"));
int by;
while ((by = bis.read()) != -1) {
bos.write(by);
}
//释放资源
bis.close();
bos.close();
}
//method4: 缓冲字节流,一次读写一个字节数组 => method4.avi
private static void method4() throws IOException {
//封装数据源
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\复制视频.avi"));
//封装目的地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d:\\method4.avi"));
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
//释放资源
bis.close();
bos.close();
}
}
3.3 转换流
c. 转换流 (字符流) = 字节流 + 编码表
- 转换流出现的原因
- 由于字节流操作中文不是特别方便,所以,java就提供了转换流
- 转换流 = 字节流 + 编码表
- 字节流读数据可能出现问题
- 字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。
- 文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
- 汉字存储的规则
- 左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。
案例代码十八 转换流出现的原因
package com.groupies.base.day13;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
/**
* @author GroupiesM
* @date 2021/04/27
* @introduction 转换流出现的原因
*
* 转换流出现的原因
* 由于字节流操作中文不是特别方便,所以,java就提供了转换流
* 转换流 = 字节流 + 编码表
*
* 字节流读数据可能出现问题
* 字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。
* 文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。
*
* 汉字存储的规则 : 左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。
*
* a.txt内容:
* hi
* 张三
*/
public class Demo18FileInputStream {
public static void main(String[] args) throws IOException {
//基本字节流一次读取一个字节
FileInputStream fis = new FileInputStream("a.txt");
int by;
while ((by = fis.read()) != -1) {
/*
hi
å¼ ä¸‰
*/
System.out.print((char) by);
}
//释放资源,刷新缓冲区
fis.close();
System.out.println("");
String s = "你";
byte[] bys = s.getBytes("GBK");
/*常见的编码表测试 中文"你"转换为字节数组
UTF-8 => [-28, -67, -96] => JDK8中不指定编码则默认为 UTF-8
GBK/GB2312 => [-60, -29] => JDK7中不指定编码则默认为 GBK/GB2312
ISO-8859-1 => [63]
ASCII => [63]
UNICODE/UTF-16 => [-2, -1, 79, 96] => UNICODE 默认使用的是UTF-16的实现方式
*/
System.out.println(Arrays.toString(bys));
}
}
3.3.1 什么是编码表
- 编码表
- 由字符及其对应的数据组成的一张表
ASCII ‘a’ 97 ‘A’ 65 ‘0’ 48
- 由字符及其对应的数据组成的一张表
-
常见的编码表
- ASCII : 美国标准信息交换码, 用一个字节的7位表示数据;(ASCII 0-126)
- ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII;
- GB2312/GBK : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII;
- UTF-8 : 使用一到四个字节来编码一个码点。, 兼容ASCII;用在网页上可以统一页面中的中文简体繁体和其他语言的显示;
- UNICODE : 为世界上所有字符都分配了一个唯一的数字编号,又称万国码;有多种实现方案(UTF-32 、UTF-16 、UTF-8)。
- 乱码问题
- 针对同一个数据, 采用的编码和解码不一致导致
- 针对同一个数据, 采用的编码和解码不一致导致
案例代码十九 遍历编码表_int转char
package com.groupies.base.day13;
/**
* @author GroupiesM
* @date 2021/04/27
* @introduction 遍历编码表_int转char
*
* 遍历ASCII码表 0~255
*/
public class Demo19ASCIIFor {
public static void main(String[] args) {
int count = 0;
for (int i = 8; i < 127; i++) {
//每打印5个换行一次
if (count == 5) {
System.out.println("");
count = 0;
}
//13换行一次,否则CR归位键会回到行最左侧位置,导致控制台打印的10-12被吞掉
if (i == 13) {
System.out.println("");
}
char ch = (char) i;
System.out.print("【" + ch + " = " + i + "】\t");
count++;
}
}
/* 8 为/b 退格
13 为\r 归为 导致 【 符号被吞掉
【 = 0】 【 = 1】 【 = 2】 【 = 3】 【 = 4】
【 = 5】 【 = 6】 【 = 7】 = 8】 【 = 9】
【
= 10】 【 = 11】 【 = 12】
= 13】 【 = 14】
【 = 15】 【 = 16】 【 = 17】 【 = 18】 【 = 19】
【 = 20】 【 = 21】 【 = 22】 【 = 23】 【 = 24】
【 = 25】 【 = 26】 【 = 27】 【 = 28】 【 = 29】
【 = 30】 【 = 31】 【 = 32】 【! = 33】 【" = 34】
【# = 35】 【$ = 36】 【% = 37】 【& = 38】 【' = 39】
【( = 40】 【) = 41】 【* = 42】 【+ = 43】 【, = 44】
【- = 45】 【. = 46】 【/ = 47】 【0 = 48】 【1 = 49】
【2 = 50】 【3 = 51】 【4 = 52】 【5 = 53】 【6 = 54】
【7 = 55】 【8 = 56】 【9 = 57】 【: = 58】 【; = 59】
【< = 60】 【= = 61】 【> = 62】 【? = 63】 【@ = 64】
【A = 65】 【B = 66】 【C = 67】 【D = 68】 【E = 69】
【F = 70】 【G = 71】 【H = 72】 【I = 73】 【J = 74】
【K = 75】 【L = 76】 【M = 77】 【N = 78】 【O = 79】
【P = 80】 【Q = 81】 【R = 82】 【S = 83】 【T = 84】
【U = 85】 【V = 86】 【W = 87】 【X = 88】 【Y = 89】
【Z = 90】 【[ = 91】 【\ = 92】 【] = 93】 【^ = 94】
【_ = 95】 【` = 96】 【a = 97】 【b = 98】 【c = 99】
【d = 100】 【e = 101】 【f = 102】 【g = 103】 【h = 104】
【i = 105】 【j = 106】 【k = 107】 【l = 108】 【m = 109】
【n = 110】 【o = 111】 【p = 112】 【q = 113】 【r = 114】
【s = 115】 【t = 116】 【u = 117】 【v = 118】 【w = 119】
【x = 120】 【y = 121】 【z = 122】 【{ = 123】 【| = 124】
【} = 125】 【~ = 126】
*/
}
3.3.2 String类的编解码
-
方法摘要
-
编码 : 把看得懂的变成看不懂的
//使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
-
解码 : 把看不懂的变成看得懂的
//通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。 public String(byte[] bytes, String charsetName)
-
- 重点强调 : 编码和解码的方式需要一致
案例代码二十 String 类的编解码
package com.groupies.base.day13;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* @author GroupiesM
* @date 2021/04/28
* @introduction String 类的编解码
*
* 方法摘要
* a.编码 : 把看得懂的变成看不懂的
* 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
* public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
*
* b.解码 : 把看不懂的变成看得懂的
* 通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。
* public String(byte[] bytes, String charsetName)
*
* 常见的编码表测试 中文"你"转换为字节数组
* UTF-8 => [-28, -67, -96] => JDK8中不指定编码则默认为 UTF-8
* GBK/GB2312 => [-60, -29] => JDK7中不指定编码则默认为 GBK/GB2312
* ISO-8859-1 => [63]
* ASCII => [63]
* UNICODE/UTF-16 => [-2, -1, 79, 96] => UNICODE 默认使用的是UTF-16的实现方式
*/
public class Demo20StringEncodeDecode {
public static void main(String[] args) throws UnsupportedEncodingException {
//定义一个字符串
String s = "你好";
//a.编码 getBytes => throws UnsupportedEncodingException 不支持的编码异常
byte[] encodeGBK = s.getBytes("GBK");
System.out.println(Arrays.toString(encodeGBK));//[-60, -29, -70, -61]
byte[] encodeUTF = s.getBytes("UTF-8");
System.out.println(Arrays.toString(encodeUTF));//[-28, -67, -96, -27, -91, -67]
//b.解码
byte[] bytesGBK = {-60, -29, -70, -61};
String decodeGBK = new String(bytesGBK);
//Java8默认编解码字符集为UTF8 用UTF8解码 GBK编码的字节码文件就会出现乱码
System.out.println(decodeGBK);//���
String decodeGBKAgain = new String(bytesGBK, "GBK");
//指定用GBK解码
System.out.println(decodeGBKAgain);//你好
byte[] bytesUTF = {-28, -67, -96, -27, -91, -67};
//不指定解码字符集,Java8环境默认使用UTF8字符集进行编解码,刚好和字节数组匹配
String decodeUTF = new String(bytesUTF);
System.out.println(decodeUTF);//你好
}
}
3.3.3 字符流Stream的编解码(写入文件)
- OutputStreamWriter 字符输出流
//根据【默认编码】把字节流的数据转换为字符流 public OutputStreamWriter(OutputStream out) //根据【指定编码】把字节流数据转换为字符流 public OutputStreamWriter(OutputStream out,String charsetName)
- InputStreamReader 字符输入流
//用【默认编码】读数据 public InputStreamReader(InputStream in) //用【指定编码】读数据 public InputStreamReader(InputStream in,String charsetName)
-
IDEA设置文件编码
查看文件结果显示是乱码,原因是输出时指定编码为GBK,java8查看默认编码为UTF-8,需要修改文件解码格式
选择 File => File Properties => File Encoding
选择GBK
重新查看文件内容,显示已正常
案例代码二十一 Stream转换流的编解码
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/04/28
* @introduction Stream转换流的编解码
*
* OutputStreamWriter 字符输出流
* public OutputStreamWriter(OutputStream out) 根据【默认编码】把字节流的数据转换为字符流
* public OutputStreamWriter(OutputStream out,String charsetName) 根据【指定编码】把字节流数据转换为字符流
*
* InputStreamReader** 字符输入流
* public InputStreamReader(InputStream in) 用【默认编码】读数据
* public InputStreamReader(InputStream in,String charsetName) 用【指定编码】读数据
*/
public class Demo21StreamEncodeDecode {
public static void main(String[] args) throws IOException {
//指定输出流 目标文件和字符集
OutputStreamWriter oswGBK = new OutputStreamWriter(new FileOutputStream("osw.txt"), "GBK");
//指定输入流 目标文件和字符集
InputStreamReader isrGBK = new InputStreamReader(new FileInputStream("osw.txt"), "GBK");
InputStreamReader isrUTF = new InputStreamReader(new FileInputStream("osw.txt"), "utf-8");
//调用写数据的方法
oswGBK.write("你好");
oswGBK.flush();//刷新缓冲流(执行一次写入)
//用GBK解码GBK文本
int byGBK;
while ((byGBK = isrGBK.read()) != -1) {
System.out.print((char) byGBK);//你好
}
System.out.println("");
//用UTF-解码GBK文本
int byUTF;
while ((byUTF = isrUTF.read()) != -1) {
System.out.print((char) byUTF);//���
}
//释放资源
oswGBK.close();
isrGBK.close();
isrUTF.close();
}
}
3.4 字符流
d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
- Reader 字符流输入超类
- InputStreamReader
- FileReader ↓作为BufferedReader构造器的参数使用↓
- e. 字符缓冲区流 BufferedReader 最常用
- InputStreamReader
- Writer 字符流输出超类
- PrintWriter
- OutputStreamWriter
- FileWriter ↓作为BufferedWriter构造器的参数使用↓
- e. 字符缓冲区流 BufferedWriter 最常用
3.4.1 复制Java文件
- 需求
- 把项目目录下的StringDemo.java内容复制到项目目录下的Copy.java中
- 三种方式
- InputStreamReader & OutputStreamWriter (字符流方式 见3.4.1) 2153毫秒
- FileReader & FileWriter (字符流方式 见3.4.1) 1957毫秒
BufferedReader & BufferedWriter(字符缓冲区流方式 见3.5.2) 2840毫秒
案例代码二十二 字符流 复制java文件
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/04/28
* @introduction 字符流 复制Java文件
*
* 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中
*
* 三种方式:
* √ 1.字符流 InputStreamReader & OutputStreamWriter
* √ 2.字符流 FileReader & FileWriter
* x 3.字符缓冲区流 BufferedReader & BufferedWriter
*/
public class Demo22StreamCopyJava {
public static void main(String[] args) throws IOException {
long start1 = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
method1("StringDemo.java","Copy.java");//method1共耗时2153毫秒
}
long end1 = System.currentTimeMillis();
System.out.println("method1共耗时" + (end1 - start1) + "毫秒");
long start2 = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
method2("StringDemo.java","Copy.java");
}
long end2 = System.currentTimeMillis();
System.out.println("method2共耗时" + (end2 - start2) + "毫秒");//method2共耗时1957毫秒
}
/**
* @introduction InputStreamReader & OutputStreamWriter
* 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中
* 数据源 : StringDemo.java---读数据---字符流---InputStreamReader
* 目的地 : Copy.java---写数据---字符流---OutputStreamWriter
*
* @param source 数据源
* @param target 目标数据
* @throws IOException
*/
public static void method1(String source, String target) throws IOException {
//封装数据源
InputStreamReader isr = new InputStreamReader(new FileInputStream(source));
//封装目的地
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(target));
//读写数据
//方式1:一次读写一个字符
/*
int ch;
while((ch= isr.read())!=-1){
osw.write(ch);
}
*/
//方式2:一次读写一个字符数组
char[] chArr = new char[1024];
int len;
while ((len = isr.read(chArr)) != -1) {
osw.write(chArr,0,len);
}
//释放资源
osw.close();
isr.close();
}
/**
* @introduction 优化method1 FileReader & FileWriter
* 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中(改进版)
* 转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类
*
* (子类)FileWriter:用来写入字符文件的便捷类
* (父类)OutputStreamWriter: FileWriter + 默认编码表(java7=GBK,java8=UTF-8)
*
* (子类)FileReader:用来读取字符文件的便捷类
* (父类)InputStreamReader: FileReader + 默认编码表(java7=GBK,java8=UTF-8)
*
* OutputStreamWriter = FileOutputStream + 默认编码表(java7=GBK,java8=UTF-8)
* FileWriter = FileOutputStream + 默认编码表(java7=GBK,java8=UTF-8)
* 构造方法:
* FileWriter(String fileName)
*
* InputStreamReader = FileInputStream + 默认编码表(java7=GBK,java8=UTF-8)
* FileReader = FileInputStream + 默认编码表(java7=GBK,java8=UTF-8)
* 构造方法:
* FileReader(String fileName)
*
* @param source 数据源
* @param target 目标数据
* @throws IOException
*/
public static void method2(String source, String target) throws IOException {
//封装数据源
FileReader fr = new FileReader(source);
//封装目的地
FileWriter fw = new FileWriter(target);
//读写数据
//方式1:一次读写一个字符
/* int ch;
while((ch= fr.read())!=-1){
fw.write(ch);
}*/
//方式2:一次读写一个字符数组
char[] chArr = new char[1024];
int len;
while ((len = fr.read(chArr)) != -1) {
fw.write(chArr,0,len);
}
//释放资源
fw.close();
fr.close();
}
}
3.4.3 OutputStreamWriter写数据的6种方式
-
方法摘要
/* @introduction 写一个字符 * @param c 要写入的字符 */ public void write(char c) /* @introduction 写一个字符 * @param c 要写入的字符对应码表中int值 */ public void write(int c) /* @introduction 写一个字符数组 * @param cbuf 要写入的字符数组 */ public void write(char[] cbuf) /* @introduction 写一个字符数组的一部分 * @param cbuf 要写入的字符数组 * @param off 起始索引 * @param len 从起始索引起,写入字符数组长度 */ public void write(char[] cbuf,int off,int len) /* @introduction 写一个字符串 * @param str 要写入的字符串 */ public void write(String str) /* @introduction 写一个字符串的一部分 * @param str 要写入的字符串 * @param off 起始索引 * @param len 从起始索引起,写入字符串长度 */ public void write(String str,int off,int len)
案例代码二十三 OutputStreamWriter写数据的6种方式
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/04/28
* @introduction OutputStreamWriter写数据的6种方式
*
* a. public void write(char c); 写一个字符
* b. public void write(int c); 写一个字符
* c. public void write(char[] cbuf); 写一个字符数组
* d. public void write(char[] cbuf,int off,int len); 写一个字符数组的一部分
* e. public void write(String str); 写一个字符串
* f. public void write(String str,int off,int len); 写一个字符串的一部分
*
* void flush():刷新该流的缓冲
* 调用close();时也会调用flush();但close()后无法继续写入
* 字节流可以直接写入,但字符流需要刷新缓冲
* 因为字符会先写入字符流缓冲区(内存),到字符流缓冲区满了才会写入一次文件
* 缓冲区写满之前需要手动flush()或调用close()才会将缓冲区字符写入目标文件(硬盘)
*
*/
public class Demo23OutputStreamWriter6Type {
public static void main(String[] args) throws IOException {
//创建字符输出流对象 (同时创建文件)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("target.txt"));
//a. public void write(char c); 写一个字符
methodA(osw);//写入一个字符a
osw.write('\r');//换行
//b. public void write(int c); 写一个字符
methodB(osw);//写入一个字符b
osw.write('\r');//换行
//c. public void write(char[] cbuf); 写一个字符数组
methodC(osw);//写入abcde
osw.write('\r');//换行
//d. public void write(char[] cbuf,int off,int len); 写一个字符数组的一部分
methodD(osw);//写入c
osw.write('\r');//换行
//e. public void write(String str); 写一个字符串
methodE(osw);//写入hello
osw.write('\r');//换行
//f. public void write(String str,int off,int len); 写一个字符串的一部分
methodF(osw);//写入lo
osw.write('\r');//换行
//释放资源
osw.close();//关闭此流,关闭前将缓冲区(内存)字符刷新(flush=>写入硬盘)
}
/**
* @introduction OutputStreamWriter写数据方式1:写一个字符
* @param osw
* @throws IOException
*/
public static void methodA(OutputStreamWriter osw) throws IOException {
//a. public void write(char c); 写一个字符
osw.write('a');
//void flush():刷新该流的缓冲
//osw.flush();
}
/**
* @introduction OutputStreamWriter写数据方式2:写一个字符
* @param osw
* @throws IOException
*/
public static void methodB(OutputStreamWriter osw) throws IOException {
//b. public void write(int c); 写一个字符
osw.write(98);
//void flush():刷新该流的缓冲
//osw.flush();
}
/**
* @introduction OutputStreamWriter写数据方式3:写一个字符数组
* @param osw
* @throws IOException
*/
public static void methodC(OutputStreamWriter osw) throws IOException {
char[] chs = {'a', 'b', 'c', 'd', 'e' };
//c. public void write(char[] cbuf); 写一个字符数组
osw.write(chs);//写入 abcde
//void flush():刷新该流的缓冲
//osw.flush();
}
/**
* @introduction OutputStreamWriter写数据方式4:写一个字符数组的一部分
* @param osw
* @throws IOException
*/
public static void methodD(OutputStreamWriter osw) throws IOException {
char[] chs = {'a', 'b', 'c', 'd', 'e' };
//d. public void write(char[] cbuf,int off,int len); 写一个字符数组的一部分
osw.write(chs, 2, 1);//写入bcd
//void flush():刷新该流的缓冲
//osw.flush();
}
/**
* @introduction OutputStreamWriter写数据方式5:写一个字符串
* @param osw
* @throws IOException
*/
public static void methodE(OutputStreamWriter osw) throws IOException {
String s = "hello";
//e. public void write(String str); 写一个字符串
osw.write(s);//写入hello
//void flush():刷新该流的缓冲
//osw.flush();
}
/**
* @introduction OutputStreamWriter写数据方式6:写一个字符串的一部分
* @param osw
* @throws IOException
*/
public static void methodF(OutputStreamWriter osw) throws IOException {
String s = "hello";
//f. public void write(String str,int off,int len); 写一个字符串的一部分
osw.write(s, 3, 2);
//void flush():刷新该流的缓冲
//osw.flush();
}
}
3.4.3 InputStreamReader读数据的2种方式
-
方法摘要
//一次读取一个字符 public int read() //一次读取一个字符数组 public int read(char[] cbuf)
案例代码二十四 InputStreamReader读数据的2种方式
package com.groupies.base.day13;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @author GroupiesM
* @date 2021/04/28
* @introduction InputStreamReader读数据的2种方式
*
* a. public int read(); 一次读取一个字符
* b. public int read(char[] cbuf); 一次读取一个字符数组
*/
public class Demo24InputStreamReader2Type {
public static void main(String[] args) throws IOException {
//创建字符流输入对象
InputStreamReader isrA = new InputStreamReader(new FileInputStream("a.txt"));
InputStreamReader isrB = new InputStreamReader(new FileInputStream("a.txt"));
//a. public int read(); 一次读取一个字符
methodA(isrA);
System.out.println("\r\n==========================");
//b. public int read(char[] cbuf); 一次读取一个字符数组
methodB(isrB);
//释放资源
isrA.close();
isrB.close();
}
/**
* @introduction InputStreamReader读数据方式1:一次读取一个字符
* @param isr
* @throws IOException
*/
public static void methodA(InputStreamReader isr) throws IOException {
int ch;
while ((ch = isr.read()) != -1) {
System.out.print((char)ch);
}
}
/**
* @introduction InputStreamReader读数据方式2:一次读取一个字符数组
* @param isr
*/
public static void methodB(InputStreamReader isr) throws IOException {
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1) {
System.out.println(new String(chs, 0, len));
}
}
}
3.5 字符缓冲区流
d. 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)
- Reader 字符流输入超类
- InputStreamReader
- FileReader ↓作为BufferedReader构造器的参数使用↓
- e. 字符缓冲区流 BufferedReader 最常用
- InputStreamReader
- Writer 字符流输出超类
- PrintWriter
- OutputStreamWriter
- FileWriter ↓作为BufferedWriter构造器的参数使用↓
- e. 字符缓冲区流 BufferedWriter 最常用
3.5.1 概述
- BufferedWriter
- 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
- 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
- 构造方法
BufferedWriter(Writer out)
- BufferedReader
- 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
- 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
- 构造方法
BufferedReader(Reader in)
案例代码二十五 字符缓冲区流概述
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/05/08
* @introduction 字符缓冲区流概述
*
* BufferedWriter
* 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
* 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。
* 构造方法:
* BufferedWriter(Writer out)
* BufferedReader
* 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
* 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
* 构造方法:
* BufferedReader(Reader in)
*/
public class Demo25Buffered {
public static void main(String[] args) throws IOException {
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
//调用写数据的方法
bw.write("hello");
//释放资源
bw.close();
//创建字符缓冲输入流对象
BufferedReader br1 = new BufferedReader(new FileReader("BufferedStreamDemo.java"));
BufferedReader br2 = new BufferedReader(new FileReader("BufferedStreamDemo.java"));
//方式1:一次读取一个字符
method1(br1);
//方式2:一次读取一个字符数组
method2(br2);
//释放资源
br1.close();
br2.close();
}
/**
* @introduction 方式1:一次读取一个字符
* @param br
* @throws IOException
*/
public static void method1(BufferedReader br) throws IOException {
int ch;
while((ch=br.read())!=-1) {
System.out.print((char)ch);
}
}
/**
* @introduction 方式2:一次读取一个字符数组
* @param br
* @throws IOException
*/
public static void method2(BufferedReader br) throws IOException {
char[] chs = new char[1024];
int len;
while ((len = br.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
}
}
3.5.2 复制文本文件
- 需求
- 把项目目录下的a.txt内容复制到项目目录下的b.txt中
- 数据源
- a.txt—读数据—字符流—InputStreamReader—FileReader—BufferedReader
- 目的地
- b.txt—写数据—字符流—OutputStreamWriter—FileWriter—BufferedWriter
案例代码二十六 字符缓冲区流 复制文本文件
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/04/28
* @introduction 字符缓冲区流 复制文本文件
*
* 需求 : 把项目目录下的a.txt内容复制到项目目录下的b.txt中
* 数据源 : a.txt---读数据---字符流---InputStreamReader---FileReader---BufferedReader
* 目的地 : b.txt---写数据---字符流---OutputStreamWriter---FileWriter---BufferedWriter
*/
public class Demo26StreamCopyTXT {
public static void main(String[] args) throws IOException {
//封装数据源
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
//读写数据
char[] chs = new char[1024];
int len;
while ((len = br.read(chs)) != -1) bw.write(chs, 0, len);
//释放资源
bw.close();
br.close();
}
}
3.5.3 复制Java文件
-
需求
- 把项目目录下的A.java内容复制到项目目录下的Copy.java中
-
三种方式
InputStreamReader & OutputStreamWriter(字符流方式 见3.4.1) 2153毫秒FileReader & FileWriter(字符流方式 见3.4.1) 1957毫秒- BufferedReader & BufferedWriter 2840毫秒
案例代码二十七 字符缓冲区流 复制Java文件
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/05/08
* @introduction 字符缓冲区流复制Java文件
*
* 需求 : 把项目目录下的StringDemo.java内容复制到项目目录下的Copy.java中
*
* 三种方式:
* x 1.字符流 InputStreamReader & OutputStreamWriter
* x 2.字符流 FileReader & FileWriter
* √ 3.字符缓冲区流 BufferedReader & BufferedWriter
*/
public class Demo27BufferedCopyJava {
public static void main(String[] args) throws IOException {
long start3 = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
method3("StringDemo.java","Copy.java");
}
long end3 = System.currentTimeMillis();
System.out.println("method3共耗时" + (end3 - start3) + "毫秒");//method3共耗时2840毫秒
}
/**
* @introduction BufferedReader & BufferedWriter
* 需求 : 把项目目录下的 StringDemo.java内容复制到项目目录下的Copy.java中
* 数据源 : StringDemo.java---读数据---字符流---InputStreamReader---FileReader---BufferedReader
* 目的地 : Copy.java---写数据---字符流---OutputStreamWriter---FileWriter---BufferedWriter
*
* @param source 数据源
* @param target 目标数据
* @throws IOException
*/
public static void method3(String source,String target) throws IOException {
//封装数据源
BufferedReader br = new BufferedReader(new FileReader(source));
//封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter(target));
//读写数据
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
}
}
3.5.4 字符缓冲区流的特殊功能
-
BufferedWriter
//写入一个行分隔符,这个行分隔符是由系统决定的 void newLine()
-
BufferedReader
//包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null String readLine()
案例代码二十八 字符缓冲区流 特殊功能
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/05/08
* @introduction 字符缓冲区流 特殊功能
*
* BufferedWriter
* a. void newLine():写入一个行分隔符,这个行分隔符是由系统决定的
*
* BufferedReader
* b. String readLine():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
*/
public class Demo28BufferedMethod {
public static void main(String[] args) throws IOException {
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
//写数据
for (int x = 0; x < 3; x++) {
bw.write("hello");
//a. void newLine():写入一个行分隔符,这个行分隔符是由系统决定的
bw.newLine();//等价于 <=> bw.write("\r\n");
bw.flush();
}
//释放资源
bw.close();
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt"));
//创建line对象接收每一行数据
String line;
//b. String readLine():包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
while ((line = br.readLine()) != null) {
/*
hello
hello
hello
*/
System.out.println(line);
}
//释放资源
br.close();
}
}
4 NIO(new IO)
- nio包在JDK4出现,提供了IO流的操作效率,但是目前还不是大范围的使用
- JDK4新IO要了解的类
- 1.Buffer(缓冲)
- 2.Channer(通道)
- JDK7新IO要了解的类:
- 3.Path:与平台无关的路径
- 4.Paths:包含了返回Path的静态方法
//4.1 根据给定的URI来确定文件路径 public static Path get(URI uri)
- 5.Files:操作文件的工具类。提供了大量方法,简单了解如下方法
//5.1 复制文件 public static long copy(Path source,OutputStream out) //5.2 把集合的数据写到文件 public static Path write(Path path,Iterable<? extends CharSequence> lines, Charset cs, OpenOption... options)
案例代码二十九 nio(new IO)简化代码
package com.groupies.base.day13;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
/**
* @author GroupiesM
* @date 2021/06/15
* @introduction nio(new IO)简化代码
*/
public class Demo29NIO {
public static void main(String[] args) throws IOException {
//5.1 复制文件
Files.copy(Paths.get("a.txt"), new FileOutputStream("copyA.txt"));
ArrayList<String> array = new ArrayList<>();
array.add("hello");
array.add("world");
array.add("java");
//5.2 把集合的数据写到文件
Files.write(Paths.get("array.txt"), array, Charset.forName("UTF-8"));
}
}
5 IO流练习
5.1 练习1 键盘写入文件
- 需求
- 请用户从控制台输入信息,程序将信息存储到文件Info.txt中。可以输入多条信息,每条信息存储一行。当用户输入:”886”时,程序结束。
练习1 Scanner通过Buffer写入文件
package com.groupies.base.day13;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
/**
* @author GroupiesM
* @date 2021/04/25
* @introduction 课后基础练习1 Scanner通过Buffer写入文件
*
* 需求:请用户从控制台输入信息,程序将信息存储到文件Info.txt中。
* 可以输入多条信息,每条信息存储一行。当用户输入:”886”时,程序结束。
*
* 123456
* abcdef
* 886
*/
public class HomeWork1Buffer {
public static void main(String[] args) throws IOException {
//1.指定输出流,对应的文件Info.txt
BufferedWriter bw = new BufferedWriter(new FileWriter("Info.txt"));
//2.采用循环的方式,把每条信息存储到一行的Info.txt中
Scanner sc = new Scanner(System.in);
while (true){
//获取键盘输入的一行内容
System.out.println("请输入内容:");
String next = sc.next();
//当用户输入886时,程序结束
if(next.equals("886")) break;
//把内容写入到Info.txt中
bw.write(next);//写入字符串
bw.newLine();//写入一个行分隔符
//bw.flush();//刷新该流的缓冲(可以省略,最后close的时候会自带一次flush)
}
bw.close();
}
}
5.2 练习2 学生信息写入文件
- 需求
- 从控制台接收3名学员的信息,每条进行存储到一个Student对象中,
- 将多个Student对象存储到一个集合中。输入完毕后,将所有学员信息存储到文件Student.txt中。
- 每名学员信息存储一行,多个属性值中间用逗号隔开。
练习2 Scanner接收学生信息写入文件 【a.实体学生类】
package com.groupies.base.day13;
/**
* @author GroupiesM
* @date 2021/04/25
* @introduction
*/
public class HomeWork2POJOStudent {
private String id;
private String name;
private String gender;
private int age;
public HomeWork2POJOStudent(String id, String name, String gender, int age) {
this.id = id;
this.name = name;
this.gender = gender;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "{id='" + id + "'" + ", name='" + name + "'" + ", gender='" + gender + "'" + ", age=" + age + '}';
}
}
练习2 Scanner接收学生信息写入文件 【b.测试类】
package com.groupies.base.day13;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
/**
* @author GroupiesM
* @date 2021/04/25
* @introduction 测试类 课后基础练习2 Scanner接收学生信息写入文件
*
* 需求:
* 从控制台接收3名学员的信息,每条进行存储到一个Student对象中,
* 将多个Student对象存储到一个集合中。输入完毕后,将所有学员信息存储到文件Student.txt中。
* 每名学员信息存储一行,多个属性值中间用逗号隔开。
* 分析:
* 1. 创建Student类,有如下属性:
* 学号、姓名、性别、年龄
* 全部属性使用String类型。要求有无参,全参构造方法。所有属性私有,并提供公有get/set方法。
* 2. 创建MainApp类,包含main()方法
* 3. 在main()方法中:
* 1) 定义一个存储Student对象的集合;
* 2) 循环3次,从控制台接收3名学员信息,每条信息封装一个Student对象,将每个Student对象存储到集合中。
* 3) 遍历集合,获取每个Student对象,取出所有属性值,输出到文件Test2_2.txt中。每名学员信息占一行。
*/
public class HomeWork2Buffer {
public static void main(String[] args) throws IOException {
//PrintWriter pw = new PrintWriter(new );
Scanner sc = new Scanner(System.in);
ArrayList<String[]> list = new ArrayList<>();
int forCount = 0;//用于循环计数
for (int i = 1; i < 4; i++) {
System.out.println("请输入第" + i + "学生信息,用逗号分隔(学号,姓名,性别,年龄)");
String strStudent = sc.next();
int commaCount = 0;//逗号计数
//校验1:判断字符串是否包含三个逗号
String temp = strStudent;
while (temp.contains(",")) {
temp = temp.substring(temp.indexOf(",") + 1);
commaCount++;
}
//如果不是三个逗号则重新输入
if (commaCount != 3) {
System.out.println("输入信息有误,请重新输入");
i--;
continue;
}
//校验2:判断输入的年龄是否为合法数字
String[] splitStudent = strStudent.split(",");
try {
Integer.parseInt(splitStudent[3]);
} catch (NumberFormatException e) {
System.out.println("输入年龄有误,请输入正确数字");
i--;
continue;
}
//将学生信息暂时放入数组缓存
list.add(splitStudent);
}
//创建字符流目标对象
BufferedWriter bw = new BufferedWriter(new FileWriter("student.txt"));
//遍历list数组中的学生信息
for (String[] sInfo : list) {
bw.write(new HomeWork2POJOStudent(sInfo[0], sInfo[1], sInfo[2], Integer.parseInt(sInfo[3])).toString());//写入字符串
bw.newLine();//写入一个行分隔符
bw.flush();//刷新该流的缓冲
}
//释放资源
bw.close();
}
}
5.3 练习3 读取文件修改指定内容
- 需求
- 将文件name.txt中的数据“卢俊义”修改为:“史文恭”。
- 在项目目录下创建文件name.txt,并写入以下内容:
it001,武松,男,22 it002,林冲,男,20 it003,卢俊义,男,18 it004,石宝,男,23
练习3 Buffer读取文件后修改指定内容并写入
package com.groupies.base.day13;
import java.io.*;
import java.util.ArrayList;
/**
* @author GroupiesM
* @date 2021/04/25
* @introduction 课后基础练习3 Buffer读取文件后修改指定内容并写入
*
* 需求:
* 将文件name.txt中的数据“卢俊义”修改为:“史文恭”。
* 在项目目录下创建文件name.txt,并写入以下内容:
* it001,武松,男,22
* it002,林冲,男,20
* it003,卢俊义,男,18
* it004,石宝,男,23
*/
public class HomeWork3Buffer {
public static void main(String[] args) throws IOException {
//指定输入流
BufferedReader br = new BufferedReader(new FileReader("name.txt"));
//定义一个数组接收学生信息
ArrayList<String[]> arrayList = new ArrayList<String[]>();
//每次读取内容
String line;
String[] strArr;
boolean b = false;
System.out.println("开始读取文件.....");
while ((line = br.readLine()) != null) {
strArr = line.split(",");
if (strArr[1].equals("卢俊义")) {
System.out.println("检测到【卢俊义】,已修改为【史文恭】");
strArr[1] = "史文恭";
b = true;
}
arrayList.add(strArr);
}
if (!b) System.out.println("未检测到【卢俊义】,无需修改文件");
if (b) {
System.out.println("开始重新写入文件....");
BufferedWriter bw = new BufferedWriter(new FileWriter("name.txt"));
for (String[] sInfo : arrayList) {
bw.write(sInfo[0] + "," + sInfo[1] + "," + sInfo[2] + "," + sInfo[3]);//写入字符串
bw.newLine();//写入一个行分隔符
bw.flush();//刷新该流的缓冲
}
//释放资源
bw.close();
try {
//尝试对此部分代码捕获异常
} catch (Exception e) {
//捕获异常后的处理逻辑
//e.printStackTrace(); //默认处理方式打印异常信息
} finally {
//无论是否捕获异常,都会执行
}
}
}
}
5.4 练习4 读取文件反转行
- 需求
- 项目根路径下有test.txt文件,内容如下:
我爱黑马 123456
- 利用IO流的知识读取text.txt文件的内容反转后写入test.txt文件中,内容如下:
123456 我爱黑马
- 项目根路径下有test.txt文件,内容如下:
练习4 读取文件反转行
package com.groupies.base.day13;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
/**
* @author GroupiesM
* @date 2021/04/25
* @introduction 数组逆序
*
* 需求:
* 项目根路径下有test.txt文件,内容如下:
* 我爱黑马
* 123456
* 利用IO流的知识读取text.txt文件的内容反转后写入test.txt文件中,内容如下:
* 123456
* 我爱黑马
*
* 思路:
* 创建集合,读取内容放入集合
* 反转集合
* 把集合内容写入源文件
* 方法:
* BufferedWriter.write(String); 写入字符串的某一部分。
* BufferedWriter.newLine(); 写入一个行分隔符。行分隔符字符串由系统属性 line.separator 定义,并且不一定是单个新行 ('\n') 符。
* BufferedWriter.flush(); 刷新该流的缓冲,也就是会把数据写入到目的文件里。如果没有在里面的for()循环中添加 bw.flush(); 这句话,
* 在循环的时候重新 new BufferedWriter();就把原来bw(缓冲区)中的覆盖掉了。于是就不能写进文件字符。
* BufferedWriter.close(); 关闭此流,关闭流前或默认先调用flush先刷新它。在关闭该流之后,再调用 write() 或 flush() 将导致抛出 IOException。关闭以前关闭的流无效。
*/
public class HomeWork4Buffer {
public static void main(String[] args) throws IOException {
//封装数据源
BufferedReader br = new BufferedReader(new FileReader("d:" + File.separator + "test.txt"));
//定义字符数组,存放读取到的数据
ArrayList<String> list = new ArrayList<String>();
//每次读取到的数据
String line;
while ((line = br.readLine()) != null) {
list.add(line);
}
//反转集合
//方式1:逆向遍历集合 list.fori
/* for (int i = 0; i < list.size() / 2; i++) {
//第一个和最后一个交换,第二个和倒数第二个交换..
String first = list.get(i);
String last = list.get(list.size() - i - 1);
list.set(i, last);//第i个值
list.set(list.size() - i - 1, last);
}*/
//方式2:Collections.revers
Collections.reverse(list);
//封装目标
BufferedWriter bw = new BufferedWriter(new FileWriter("d:" + File.separator + "test.txt"));
//写入数据
for (int i = 0; i < list.size(); i++) {
//写入字符串
//bw.write(list.get(i), 0, list.get(i).length());
bw.write(list.get(i));
//写入一个行分隔符
bw.newLine();
bw.flush();//将缓冲区内容 写入目标文件
}
//释放资源
br.close();
bw.close();
}
}
5.5 练习5 字符流五种方式读写
- 需求
- 复制文件到指定目录(字符流五种方式)
- 数据源:
- d:\林青霞.txt
- 目标:
- 窗里窗外.txt
-
字符流五种方式
-
基本字符流
FileReader
-
基本字符流一次读写一个字符
//method1 int ch; while ((ch = fr.read()) != -1) { fw.write(ch); }
-
基本字符流一次读写一个字符数组
//method2 char[] chs = new char[1024]; int len; while((len=fr.read(chs))!=-1) { fw.write(chs, 0, len); }
-
-
缓冲字符流
BufferedReader
-
缓冲字符流一次读写一个字符
//method3 int ch; while((ch=br.read())!=-1) { bw.write(ch); }
-
缓冲字符流一次读写一个字符数组
//method4 char[] chs = new char[1024]; int len; while((len=br.read(chs))!=-1) { bw.write(chs, 0, len); }
-
缓冲字符串一次读写一行
//method5 String line; while((line=br.readLine())!=null) { bw.write(line); bw.newLine(); bw.flush(); }
-
-
- 注意
- 因为这五种方法读取数据时不能指定编码,所以写入数据时一定要注意读写编码一致(
默认编码 JDK7 GBK / JDK8 UTF-8
)
- 因为这五种方法读取数据时不能指定编码,所以写入数据时一定要注意读写编码一致(
练习5 字符流复制文本文件的五种方式
package com.groupies.base.day13;
import java.io.*;
/**
* @author GroupiesM
* @date 2021/05/10
* @introduction 字符流复制文本文件的五种方式
*
* 需求:
* 复制文件到指定目录(字符流五种方式)
* 数据源:
* d:\\林青霞.txt
* 目标:
* 窗里窗外.txt
*
*
* 五种方式:
* 基本字符流一次读写一个字符
* 基本字符流一次读写一个字符数组
* 缓冲字符流一次读写一个字符
* 缓冲字符流一次读写一个字符数组
* 缓冲字符串一次读写一行
*
* 注意:
* 因为这五种方法读取数据时不能指定编码,所以写入数据时一定要注意读写编码一致(默认编码 JDK7 GBK / JDK8 UTF-8)
*/
public class HomeWork5CopyTxt {
public static void main(String[] args) throws IOException {
/*
创建数据源 d:\\林青霞.txt
使用java8环境(默认读写字符集为UTF-8)
因为这五种方法读取数据时不能指定编码,所以写入数据时一定要注意读写编码一致(默认编码 JDK7 GBK / JDK8 UTF-8)
*/
createFile();
//基本字符流一次读写一个字符
Long start1 = System.currentTimeMillis();
method1("d:" + File.separator + "林青霞.txt", "窗里窗外1.txt");
Long end1 = System.currentTimeMillis();
System.out.println("method1共耗时:" + (end1 - start1) + "毫秒");//method1共耗时:436毫秒
//基本字符流一次读写一个字符数组
Long start2 = System.currentTimeMillis();
method2("d:" + File.separator + "林青霞.txt", "窗里窗外2.txt");//method2共耗时:43毫秒
Long end2 = System.currentTimeMillis();
System.out.println("method2共耗时:" + (end2 - start2) + "毫秒");
//缓冲字符流一次读写一个字符
Long start3 = System.currentTimeMillis();
method3("d:" + File.separator + "林青霞.txt", "窗里窗外3.txt");//method3共耗时:22毫秒
Long end3 = System.currentTimeMillis();
System.out.println("method3共耗时:" + (end3 - start3) + "毫秒");
//缓冲字符流一次读写一个字符数组
Long start4 = System.currentTimeMillis();
method4("d:" + File.separator + "林青霞.txt", "窗里窗外4.txt");//method4共耗时:22毫秒
Long end4 = System.currentTimeMillis();
System.out.println("method4共耗时:" + (end4 - start4) + "毫秒");
//缓冲字符串一次读写一行
Long start5 = System.currentTimeMillis();
method5("d:" + File.separator + "林青霞.txt", "窗里窗外5.txt");//method5共耗时:22毫秒
Long end5 = System.currentTimeMillis();
System.out.println("method5共耗时:" + (end5 - start5) + "毫秒");
}
/**
* @introduction 创建数据源 d:\\林青霞.txt 供下一步读取使用
* @throws IOException
*/
public static void createFile() throws IOException {
//指定输出流 目标文件和字符集
OutputStreamWriter oswGBKSource = new OutputStreamWriter(new FileOutputStream("d:\\林青霞.txt"), "UTF-8");
oswGBKSource.write("林青霞1\r\n");
oswGBKSource.write("林青霞2\r\n");
oswGBKSource.write("林青霞3\r\n");
oswGBKSource.close();
}
/**
* @introduction 基本字符流一次读写一个字符
* @param source 数据源
* @param target 目标文件
* @throws IOException
*/
private static void method1(String source, String target) throws IOException {
FileReader fr = new FileReader(source);
FileWriter fw = new FileWriter(target);
int ch;
while ((ch = fr.read()) != -1) {
fw.write(ch);
}
fw.close();
fr.close();
}
/**
* @introduction 基本字符流一次读写一个字符数组
* @param source 数据源
* @param target 目标文件
* @throws IOException
*/
private static void method2(String source, String target) throws IOException {
FileReader fr = new FileReader(source);
FileWriter fw = new FileWriter(target);
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1) {
fw.write(chs, 0, len);
}
fw.close();
fr.close();
}
/**
* @introduction 缓冲字符流一次读写一个字符
* @param source 数据源
* @param target 目标文件
* @throws IOException
*/
private static void method3(String source, String target) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(source));
BufferedWriter bw = new BufferedWriter(new FileWriter(target));
int ch;
while ((ch = br.read()) != -1) {
bw.write(ch);
}
bw.close();
br.close();
}
/**
* @introduction 缓冲字符流一次读写一个字符数组
* @param source 数据源
* @param target 目标文件
* @throws IOException
*/
private static void method4(String source, String target) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(source));
BufferedWriter bw = new BufferedWriter(new FileWriter(target));
char[] chs = new char[1024];
int len;
while ((len = br.read(chs)) != -1) {
bw.write(chs, 0, len);
}
bw.close();
br.close();
}
/**
* @introduction 缓冲字符流一次读写一个字符串
* @param source 数据源
* @param target 目标文件
* @throws IOException
*/
private static void method5(String source, String target) throws IOException {
BufferedReader br = new BufferedReader(new FileReader(source));
BufferedWriter bw = new BufferedWriter(new FileWriter(target));
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
5.6 练习6 ArrayList到TXT
- 需求
- A:创建集合对象
- B:往集合中添加字符串元素
- C:创建字符缓冲输出流对象
- D:遍历集合,得到每一个字符串元素,把字符串元素作为数据写入到文本文件
- E:释放资源
练习6 字符流-ArrayList到TXT
package com.groupies.base.day13;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author GroupiesM
* @date 2021/05/10
* @introduction 字符流-ArrayList到TXT
*
* 需求:
* A:创建集合对象
* B:往集合中添加字符串元素
* C:创建字符缓冲输出流对象
* D:遍历集合,得到每一个字符串元素,把字符串元素作为数据写入到文本文件
* E:释放资源
*/
public class HomeWork6ArrayListToTxt {
public static void main(String[] args) throws IOException {
//创建集合对象
ArrayList<String> array = new ArrayList<>();
//往集合中添加字符串元素
array.add("hello");
array.add("world");
array.add("java");
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("array.txt"));
//遍历集合,得到每一个字符串元素,把字符串元素作为数据写入到文本文件
for (String s : array) {
bw.write(s);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
}
}
5.7 练习7 TXT到ArrayList
- 需求
- 从文本文件中读取数据到ArrayList集合中,并遍历集合
- 每一行数据作为一个字符串元素
- 数据源
- 练习6中生成的文件
student.txt
- 练习6中生成的文件
- 分析
- A:创建字符缓冲输入流对象
- B:创建集合对象
- C:读取数据,每一次读取一行,并把该数据作为元素存储到集合中
- D:释放资源
- E:遍历集合
练习7 字符流-TXT到ArrayList
package com.groupies.base.day13;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author GroupiesM
* @date 2021/05/10
* @introduction
*
* 需求:
* 从文本文件中读取数据到ArrayList集合中,并遍历集合
* 每一行数据作为一个字符串元素
*
* 分析:
* A:创建字符缓冲输入流对象
* B:创建集合对象
* C:读取数据,每一次读取一行,并把该数据作为元素存储到集合中
* D:释放资源
* E:遍历集合
*/
public class HomeWork7TxtToArrayList {
//指定数据源
final static String sourceFile = "array.txt";
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader(sourceFile));
//创建集合对象
ArrayList<String> array = new ArrayList<>();
//读取数据,每次读取一行,并把改数据作为元素存储到集合中
String line;
while ((line = br.readLine()) != null) {
array.add(line);
}
//释放资源
br.close();
//遍历集合
for (String s : array) {
System.out.println(s);
}
}
}
5.8 练习8 Array<Student>到TXT
-
需求
- 把ArrayList集合中的学生数据存储到文本文件
- 每一个学生数据作为文件中的一行数据
-
定义一个学生类
- 学生:
- 学号,姓名,年龄,所在城市
it001,张曼玉,35,北京 it002,王祖贤,33,上海 it003,林青霞,30,西安
- 学号,姓名,年龄,所在城市
- 学生:
- 分析
- A:创建集合对象
- B:创建学生对象
- C:把学生对象添加到集合中
- D:创建字符缓冲输出流对象
- E:遍历集合,得到每一个学生对象,然后把该对象的数据拼接成一个指定格式的字符串写到文本文件
- F:释放资源
练习8 Array<Student>到TXT 【a.学生类】
package com.groupies.base.day13;
/**
* @author GroupiesM
* @date 2021/05/10
* @introduction
*/
public class HomeWork8POJOStudent {
private String id;
private String name;
private int age;
private String location;
public HomeWork8POJOStudent() {
}
public HomeWork8POJOStudent(String id, String name, int age, String location) {
this.id = id;
this.name = name;
this.age = age;
this.location = location;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
/**
* @introduction 逗号分隔学生信息
* @return
*/
@Override
public String toString() {
return id + "," + name + "," + age + "," + location;
}
}
练习8 Array<Student>到TXT 【b.测试类】
package com.groupies.base.day13;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author GroupiesM
* @date 2021/05/10
* @introduction
*/
public class HomeWork8ArrayListToTxt {
//写入目标文件
final static String targetFile = "student.txt";
public static void main(String[] args) throws IOException {
//创建集合对象
ArrayList<HomeWork8POJOStudent> array = new ArrayList<>();
//创建学生对象
HomeWork8POJOStudent s1 = new HomeWork8POJOStudent("it001", "张曼玉", 35, "北京");
HomeWork8POJOStudent s2 = new HomeWork8POJOStudent("it002", "王祖贤", 33, "上海");
HomeWork8POJOStudent s3 = new HomeWork8POJOStudent("it003", "林青霞", 30, "西安");
// 把学生对象添加到集合中
array.add(s1);
array.add(s2);
array.add(s3);
//创建字符缓冲流输出对象
BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile));
//拼接学生信息到字符串中
StringBuilder sb = new StringBuilder();
//遍历集合,得到每一个学生对象,然后把该对象的数据接成一个指定格式的字符串写到文本文件
for (HomeWork8POJOStudent s : array) {
sb.append(s.toString());
sb.append("\r\n");
}
/*
正在将以下信息写入目标文件=>student.txt
it001,张曼玉,35,北京
it002,王祖贤,33,上海
it003,林青霞,30,西安
*/
System.out.println("正在将以下信息写入目标文件=>" + targetFile);
System.out.println(sb);
bw.write(sb.toString());
//刷新缓存并释放资源 flush
bw.close();
}
}
5.9 练习9 TXT到Array<Student>
- 需求
- 从文本文件中读取学生数据到ArrayList集合中,并遍历集合
- 每一行数据作为一个学生元素
it001,张曼玉,35,北京 it002,王祖贤,33,上海 it003,林青霞,30,西安
- 这里我们要使用String类中的一个方法:split()
- 数据源
- 练习8中生成的文件
student.txt
- 练习8中生成的文件
- 分析
- A:创建字符缓冲输入流对象
- B:创建集合对象
- C:读取数据,每一次读取一行数据,把该行数据想办法封装成学生对象,并把学生对象存储到集合中
- D:释放资源
- E:遍历集合
练习9 Array<Student>到TXT 【a.学生类】
package com.groupies.base.day13;
/**
* @author GroupiesM
* @date 2021/05/10
* @introduction
*/
public class HomeWork9POJOStudent {
private String id;
private String name;
private int age;
private String location;
public HomeWork9POJOStudent() {
}
public HomeWork9POJOStudent(String id, String name, int age, String location) {
this.id = id;
this.name = name;
this.age = age;
this.location = location;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
@Override
public String toString() {
return "{" + "id='" + id + "', name='" + name + "', age=" + age + ", location='" + location + "'" + '}';
}
}
练习9 Array<Student>到TXT 【b.测试类】
package com.groupies.base.day13;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author GroupiesM
* @date 2021/05/10
* @introduction
*/
public class HomeWork9TxtToArrayList {
//指定数据源
final static String sourceFile = "student.txt";
public static void main(String[] args) throws IOException {
//创建字符缓冲输入流对象
BufferedReader br = new BufferedReader(new FileReader(sourceFile));
//创建集合对象
ArrayList<HomeWork9POJOStudent> array = new ArrayList<>();
//读取数据,每次读取一行数据,把该行业数据想办法封装成学生对象,并把学生对象存储到集合中
String line;
HomeWork9POJOStudent student;
while ((line = br.readLine()) != null) {
//按逗号分隔字符串对象,存入字符数组
String[] strArray = line.split(",");
student = new HomeWork9POJOStudent();
student.setId(strArray[0]);
student.setName(strArray[1]);
student.setAge(Integer.parseInt(strArray[2]));
student.setLocation(strArray[3]);
array.add(student);
}
// 释放资源
br.close();
// 遍历集合
for (HomeWork9POJOStudent s : array) {
/*
{id='it001', name='张曼玉', age=35, location='北京'}
{id='it002', name='王祖贤', age=33, location='上海'}
{id='it003', name='林青霞', age=30, location='西安'}
*/
System.out.println(s.toString());
}
}
}
21/05/10
M