1. 字节缓冲流
1.1 字节缓冲流构造方法
- 字节缓冲流介绍
- BufferedOutputStream :该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
- BufferedInputStream :创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
- 构造方法:
方法名 | 说明 |
---|
BufferedOutputStream(OutputStream out) | 创建字节缓冲输出流对象 |
BufferedInputStream(InputStream in) | 创建字节缓冲输入流对象 |
public class BufferStreamDemo {
public static void main(String[] args) throws IOException {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\bos.txt"));
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
bos.close();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("myByteStream\\bos.txt"));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
bis.close();
}
}
1.2 字节流复制视频
- 案例需求
把“E:\itcast\字节流复制图片.avi”复制到模块目录下的“字节流复制图片.avi” - 实现步骤
- 根据数据源创建字节输入流对象
- 根据目的地创建字节输出流对象
- 读写数据,复制视频
- 释放资源
- 代码实现
public class CopyAviDemo {
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
method4();
long endTime = System.currentTimeMillis();
System.out.println("共耗时:" + (endTime - startTime) + "毫秒");
}
public static void method4() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\itcast\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
public static void method3() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\itcast\\字节流复制图片.avi"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("myByteStream\\字节流复制图片.avi"));
int by;
while ((by=bis.read())!=-1) {
bos.write(by);
}
bos.close();
bis.close();
}
public static void method2() throws IOException {
FileInputStream fis = new FileInputStream("E:\\itcast\\字节流复制图片.avi");
FileOutputStream fos = new FileOutputStream("myByteStream\\字节流复制图片.avi");
byte[] bys = new byte[1024];
int len;
while ((len=fis.read(bys))!=-1) {
fos.write(bys,0,len);
}
fos.close();
fis.close();
}
public static void method1() throws IOException {
FileInputStream fis = new FileInputStream("E:\\itcast\\字节流复制图片.avi");
FileOutputStream fos = new FileOutputStream("myByteStream\\字节流复制图片.avi");
int by;
while ((by=fis.read())!=-1) {
fos.write(by);
}
fos.close();
fis.close();
}
}
2. 字符流
2.1 为什么会出现字符流
- 字符流的介绍
- 由于字节流操作中文不是特别的方便,所以Java就提供字符流
- 字符流 = 字节流 + 编码表
- 中文的字节存储方式
- 用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文,如何识别是中文的呢?
- 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
2.2 编码表
- 什么是字符集
- 是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
- 计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
-
- ASCII 字符集:
ASCII:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、
换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等 - GBXXX 字符集:
GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等 - Unicode 字符集:
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用
中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
编码规则:
128个US-ASCII字符,只需一个字节编码
拉丁文等字符,需要二个字节编码
大部分常用字(含中文),使用三个字节编码
其他极少使用的Unicode辅助字符,使用四字节编码
如果是GBK编码,占用2个字节
如果是UTF-8编码,占用3个字节
2.3 字符串中的编码解码问题
方法名 | 说明 |
---|
byte[] getBytes() | 使用平台的默认字符集将该 String编码为一系列字节 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该 String编码为一系列字节 |
String(byte[] bytes) | 使用平台的默认字符集解码指定的字节数组来创建字符串 |
String(byte[] bytes, String charsetName) | 通过指定的字符集解码指定的字节数组来创建字符串 |
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "中国";
byte[] bys = s.getBytes("GBK");
System.out.println(Arrays.toString(bys));
String ss = new String(bys,"GBK");
System.out.println(ss);
}
}
2.4 字符流中的编码解码问题
- 字符流中和编码解码问题相关的两个类
- InputStreamReader :是从字节流到字符流的桥梁
- 它读取字节,并使用指定的编码将其解码为字符
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
- OutputStreamWriter :是从字符流到字节流的桥梁
- 是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
方法名 | 说明 |
---|
InputStreamReader(InputStream in) | 使用默认字符编码创建InputStreamReader对象 |
InputStreamReader(InputStream in,String charset) | 使用指定的字符编码创建InputStreamReader对象 |
OutputStreamWriter(OutputStream out) | 使用默认字符编码创建OutputStreamWriter对象 |
OutputStreamWriter(OutputStream out,String charset) | 使用指定的字符编码创建OutputStreamWriter对象 |
public class ConversionStreamDemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"),"GBK");
osw.write("中国");
osw.close();
InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\osw.txt"),"GBK");
int ch;
while ((ch=isr.read())!=-1) {
System.out.print((char)ch);
}
isr.close();
}
}
2.5 字符流写数据的5种方式
方法名 | 说明 |
---|
void write(int c) | 写一个字符 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
方法名 | 说明 |
---|
flush() | 刷新操作后数据才写进去(存在缓存),释放资源前JVM自动刷新一次。刷新流,之后还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("myCharStream\\osw.txt"));
char[] chs = {'a', 'b', 'c', 'd', 'e'};
osw.write("abcde", 1, 3);
osw.close();
}
}
2.6 字符流读数据的2种方式
方法名 | 说明 |
---|
int read() | 一次读一个字符数据 |
int read(char[] cbuf) | 一次读一个字符数组数据 |
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("myCharStream\\ConversionStreamDemo.java"));
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1) {
System.out.print(new String(chs, 0, len));
}
isr.close();
}
}
2.7 字符流复制Java文件
- 案例需求
把模块目录下的“ConversionStreamDemo.java” 复制到模块目录下的“Copy.java” - 实现步骤
- 根据数据源创建字符输入流对象
- 根据目的地创建字符输出流对象
- 读写数据,复制文件
- 释放资源
- 代码实现
public class CopyJavaDemo01 {
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new
FileInputStream("myCharStream\\ConversionStreamDemo.java"));
OutputStreamWriter osw = new OutputStreamWriter(new
FileOutputStream("myCharStream\\Copy.java"));
char[] chs = new char[1024];
int len;
while ((len=isr.read(chs))!=-1) {
osw.write(chs,0,len);
}
osw.close();
isr.close();
}
}
2.8 字符流复制Java文件改进版
public class CopyJavaDemo02 {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("myCharStream\\ConversionStreamDemo.java");
FileWriter fw = new FileWriter("myCharStream\\Copy.java");
char[] chs = new char[1024];
int len;
while ((len=fr.read(chs))!=-1) {
fw.write(chs,0,len);
}
fw.close();
fr.close();
}
}
2.9 字符缓冲流
- 字符缓冲流介绍
- BufferedWriter :将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
- BufferedReader :从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
- 构造方法
方法名 | 说明 |
---|
BufferedWriter(Writer out) | 创建字符缓冲输出流对象 |
BufferedReader(Reader in) | 创建字符缓冲输入流对象 |
public class BufferedStreamDemo01 {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
br.close();
}
}
2.10 字符缓冲流复制Java文件
- 案例需求
把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java - 实现步骤
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件,使用字符缓冲流特有功能实现
- 释放资源
- 代码实现
public class CopyJavaDemo01 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\ConversionStreamDemo.java"));
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\Copy.java"));
char[] chs = new char[1024];
int len;
while ((len=br.read(chs))!=-1) {
bw.write(chs,0,len);
}
bw.close();
br.close();
}
}
2.11 字符缓冲流特有功能
方法名 | 说明 |
---|
void newLine() | 写一行行分隔符,行分隔符字符串由系统属性定义 |
方法名 | 说明 |
---|
String readLine() | 读一行文字。 结果包含行的内容的字符串,不包括任何行终止字符如果流的结尾已经到达,则为null |
public class BufferedStreamDemo02 {
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\bw.txt"));
for (int i = 0; i < 10; i++) {
bw.write("hello" + i);
bw.newLine();
bw.flush();
}
bw.close();
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\bw.txt"));
String line;
while ((line=br.readLine())!=null) {
System.out.println(line);
}
br.close();
}
}
2.12 字符缓冲流特有功能复制Java文件
- 案例需求
使用特有功能把模块目录下的ConversionStreamDemo.java 复制到模块目录下的 Copy.java - 实现步骤
- 根据数据源创建字符缓冲输入流对象
- 根据目的地创建字符缓冲输出流对象
- 读写数据,复制文件,使用字符缓冲流特有功能实现
- 释放资源
- 代码实现
public class CopyJavaDemo02 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\ConversionStreamDemo.java"));
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\Copy.java"));
String line;
while ((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
}
2.13 IO流小结
- 字节流
- 字符流
3. 练习案例
3.1 集合到文件
- 案例需求
把文本文件中的数据读取到集合中,并遍历集合。要求:文件中每一行数据是一个集合元素 - 实现步骤
- 创建字符缓冲输入流对象
- 创建 ArrayList集合对象
- 调用字符缓冲输入流对象的方法读数据
- 把读取到的字符串数据存储到集合中
- 释放资源
- 遍历集合
- 代码实现
public class ArrayListToTxtDemo {
public static void main(String[] args) throws IOException {
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\array.txt"));
for(String s : array) {
bw.write(s);
bw.newLine();
bw.flush();
}
bw.close();
}
}
3.2 文件到集合
- 案例需求
把ArrayList集合中的字符串数据写入到文本文件。要求:每一个字符串元素作为文件中的一行数据 - 实现步骤
- 创建 ArrayList集合
- 往集合中存储字符串元素
- 创建字符缓冲输出流对象
- 遍历集合,得到每一个字符串数据
- 调用字符缓冲输出流对象的方法写数据
- 释放资源
- 代码实现
public class TxtToArrayListDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\array.txt"));
ArrayList<String> array = new ArrayList<String>();
String line;
while ((line=br.readLine())!=null) {
array.add(line);
}
br.close();
for(String s : array) {
System.out.println(s);
}
}
}
3.3 点名器
- 案例需求
我有一个文件里面存储了班级同学的姓名,每一个姓名占一行,要求通过程序实现随点名器 - 实现步骤
- 创建字符缓冲输入流对象
- 创建 ArrayList集合对象
- 调用字符缓冲输入流对象的方法读数据
- 把读取到的字符串数据存储到集合中
- 释放资源
- 使用 Random产生一个随机数,随机数的范围在:[0,集合的长度)
- 把第 6步产生的随机数作为索引到ArrayList集合中获取值
- 把第 7步得到的数据输出在控制台
- 代码实现
public class CallNameDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\names.txt"));
ArrayList<String> array = new ArrayList<String>();
String line;
while ((line=br.readLine())!=null) {
array.add(line);
}
br.close();
Random r = new Random();
int index = r.nextInt(array.size());
String name = array.get(index);
System.out.println("幸运者是:" + name);
}
}
3.4 集合到文件改进版
- 案例需求
把ArrayList集合中的学生数据写入到文本文件。要求:每一个学生对象的数据作为文件中的一行数据 格式:学号,姓名,年龄,居住地 举例:itheima001,林青霞,30,西安 - 实现步骤
- 定义学生类
- 创建 ArrayList集合
- 创建学生对象
- 把学生对象添加到集合中
- 创建字符缓冲输出流对象
- 遍历集合,得到每一个学生对象
- 把学生对象的数据拼接成指定格式的字符串
- 调用字符缓冲输出流对象的方法写数据
- 释放资源
- 代码实现
学生类
public class Student {
private String sid;
private String name;
private int age;
private String address;
public Student() {
}
public Student(String sid, String name, int age, String address) {
this.sid = sid;
this.name = name;
this.age = age;
this.address = address;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
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 getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
测试类
public class ArrayListToFileDemo {
public static void main(String[] args) throws IOException {
ArrayList<Student> array = new ArrayList<Student>();
Student s1 = new Student("itheima001", "林青霞", 30, "西安");
Student s2 = new Student("itheima002", "张曼玉", 35, "武汉");
Student s3 = new Student("itheima003", "王祖贤", 33, "郑州");
array.add(s1);
array.add(s2);
array.add(s3);
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\students.txt"));
for (Student s : array) {
StringBuilder sb = new StringBuilder();
sb.append(s.getSid()).append(",").append(s.getName()).append(",").append(s.ge
tAge()).append(",").append(s.getAddress());
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
bw.close();
}
}
3.5 文件到集合改进版
- 案例需求
把文本文件中的数据读取到集合中,并遍历集合。要求:文件中每一行数据是一个学生对象的成员变量值 举例:itheima001,林青霞,30,西安 - 实现步骤
- 定义学生类
- 创建字符缓冲输入流对象
- 创建 ArrayList集合对象
- 调用字符缓冲输入流对象的方法读数据
- 把读取到的字符串数据用 split()进行分割,得到一个字符串数组
- 创建学生对象
- 把字符串数组中的每一个元素取出来对应的赋值给学生对象的成员变量值
- 把学生对象添加到集合
- 释放资源
- 遍历集合
- 代码实现
学生类
同上
测试类
public class FileToArrayListDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myCharStream\\students.txt"));
ArrayList<Student> array = new ArrayList<Student>();
String line;
while ((line = br.readLine()) != null) {
String[] strArray = line.split(",");
Student s = new Student();
s.setSid(strArray[0]);
s.setName(strArray[1]);
s.setAge(Integer.parseInt(strArray[2]));
s.setAddress(strArray[3]);
array.add(s);
}
br.close();
for (Student s : array) {
System.out.println(s.getSid() + "," + s.getName() + "," + s.getAge() + "," + s.getAddress());
}
}
}
4. IO 流案例
4.1 集合到文件数据排序改进版
- 案例需求
键盘录入 5个学生信息(姓名,语文成绩,数学成绩,英语成绩)。要求按照成绩总分从高到低写入文本文件
格式:姓名 ,语文成绩,数学成绩,英语成绩 举例:林青霞,98,99,100 - 分析步骤
- 定义学生类
- 创建TreeSet集合,通过比较器排序进行排序
- 键盘录入学生数据
- 创建学生对象,把键盘录入的数据对应赋值给学生对象的成员变量
- 把学生对象添加到TreeSet集合
- 创建字符缓冲输出流对象
- 遍历集合,得到每一个学生对象
- 把学生对象的数据拼接成指定格式的字符串
- 调用字符缓冲输出流对象的方法写数据
- 释放资源
- 代码实现
学生类
public class Student {
private String name;
private int chinese;
private int math;
private int english;
public Student() {
super();
}
public Student(String name, int chinese, int math, int english) {
super();
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
public int getSum() {
return this.chinese + this.math + this.english;
}
}
测试类
public class TreeSetToFileDemo {
public static void main(String[] args) throws IOException {
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getSum() - s1.getSum();
int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
int num4 = num3 == 0 ? s1.getName().compareTo(s2.getName()) : num3;
return num4;
}
});
for (int i = 0; i < 5; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("请录入第" + (i + 1) + "个学生信息:");
System.out.println("姓名:");
String name = sc.nextLine();
System.out.println("语文成绩:");
int chinese = sc.nextInt();
System.out.println("数学成绩:");
int math = sc.nextInt();
System.out.println("英语成绩:");
int english = sc.nextInt();
Student s = new Student();
s.setName(name);
s.setChinese(chinese);
s.setMath(math);
s.setEnglish(english);
ts.add(s);
}
BufferedWriter bw = new BufferedWriter(new FileWriter("myCharStream\\ts.txt"));
for (Student s : ts) {
StringBuilder sb = new StringBuilder();
sb.append(s.getName()).append(",").append(s.getChinese()).append(",").append(s
.getMath()).append(",").append(s.getEnglish()).append(",").append(s.getSum());
bw.write(sb.toString());
bw.newLine();
bw.flush();
}
bw.close();
}
}
4.2 复制单级文件夹
- 案例需求
- 把 “E:\itcast”这个文件夹复制到模块目录下
- 分析步骤
- 创建数据源目录File对象,路径是E:\itcast
- 获取数据源目录File对象的名称
- 创建目的地目录File对象,路径由(模块名+第2步获取的名称)组成
- 判断第3步创建的File是否存在,如果不存在,就创建
- 获取数据源目录下所有文件的File数组
- 遍历File数组,得到每一个File对象,该File对象,其实就是数据源文件
- 获取数据源文件File对象的名称
- 创建目的地文件File对象,路径由(目的地目录+第7步获取的名称)组成
- 复制文件
由于不清楚数据源目录下的文件都是什么类型的,所以采用字节流复制文件
采用参数为File的构造方法
- 代码实现
public class CopyFolderDemo {
public static void main(String[] args) throws IOException {
File srcFolder = new File("E:\\itcast");
String srcFolderName = srcFolder.getName();
File destFolder = new File("myCharStream",srcFolderName);
if(!destFolder.exists()) {
destFolder.mkdir();
}
File[] listFiles = srcFolder.listFiles();
for(File srcFile : listFiles) {
String srcFileName = srcFile.getName();
File destFile = new File(destFolder,srcFileName);
copyFile(srcFile,destFile);
private static void copyFile(File srcFile, File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bys = new byte[1024];
int len;
while ((len=bis.read(bys))!=-1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
}
4.3 复制多级文件夹
- 案例需求
把 “E:\itcast”这个文件夹复制到 F盘目录下 - 分析步骤
- 创建数据源File对象,路径是E:\itcast
- 创建目的地File对象,路径是F:\
- 写方法实现文件夹的复制,参数为数据源File对象和目的地File对象
- 判断数据源File是否是文件
- 是文件:直接复制,用字节流
- 不是文件:
- 在目的地下创建该目录
- 遍历获取该目录下的所有文件的File数组,得到每一个File对象
- 回到3继续(递归)
- 代码实现
public class CopyFoldersDemo {
public static void main(String[] args) throws IOException {
File srcFile = new File("E:\\itcast");
File destFile = new File("F:\\");
copyFolder(srcFile,destFile);
}
private static void copyFolder(File srcFile, File destFile) throws IOException{
if(srcFile.isDirectory()) {
String srcFileName = srcFile.getName();
File newFolder = new File(destFile,srcFileName);
if(!newFolder.exists()) {
newFolder.mkdir();
}
File[] fileArray = srcFile.listFiles();
for(File file : fileArray) {
copyFolder(file,newFolder);
}
} else {
File newFile = new File(destFile,srcFile.getName());
copyFile(srcFile,newFile);
}
}
private static void copyFile(File srcFile, File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bys = new byte[1024];
int len;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
bis.close();
}
}
4.4 复制文件的异常处理
-
常见方法
-
代码实现
public class CopyFileDemo {
public static void main(String[] args) {
}
private static void method2() {
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader("fr.txt");
fw = new FileWriter("fw.txt");
char[] chs = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(fw!=null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fr!=null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static void method1() throws IOException {
FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt");
char[] chs = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chs, 0, len);
}
fw.close();
fr.close();
}
}
public class CopyFileDemo {
public static void main(String[] args) {
}
private static void method3() {
try(FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt");){
char[] chs = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class CopyFileDemo {
public static void main(String[] args) {
}
private static void method4() throws IOException {
FileReader fr = new FileReader("fr.txt");
FileWriter fw = new FileWriter("fw.txt");
try(fr;fw){
char[] chs = new char[1024];
int len;
while ((len = fr.read()) != -1) {
fw.write(chs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
5. IO 特殊操作流
5.1 标准输入流
- System 类中有两个静态的成员变量
- public static final InputStream in :标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
- public static final PrintStream out :标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
- 自己实现键盘录入数据
public class SystemInDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入一个字符串:");
String line = br.readLine();
System.out.println("你输入的字符串是:" + line);
System.out.println("请输入一个整数:");
int i = Integer.parseInt(br.readLine());
System.out.println("你输入的整数是:" + i);
Scanner sc = new Scanner(System.in);
}
}
5.2 标准输出流
- System 类中有两个静态的成员变量
- public static final InputStream in :标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
- public static final PrintStream out :标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
- 输出语句的本质:是一个标准的输出流
- PrintStream ps = System.out;
- PrintStream 类有的方法,System.out都可以使用
- 示例代码
public class SystemOutDemo {
public static void main(String[] args) {
PrintStream ps = System.out;
System.out.println("hello");
System.out.println(100);
System.out.println();
}
}
5.3 字节打印流
- 打印流分类
- 字节打印流: PrintStream
- 字符打印流: PrintWriter
- 打印流的特点
- 只负责输出数据,不负责读取数据
- 永远不会抛出 IOException
- 有自己的特有方法
- 字节打印流
- PrintStream(String fileName) :使用指定的文件名创建新的打印流
- 使用继承父类的方法写数据,查看的时候会转码;使用自己的特有方法写数据,查看的数据原样输出
- 可以改变输出语句的目的地
public static void setOut(PrintStream out):重新分配“标准”输出流
- 示例代码
public class PrintStreamDemo {
public static void main(String[] args) throws IOException {
PrintStream ps = new PrintStream("myOtherStream\\ps.txt");
ps.println(97);
ps.println(98);
ps.close();
}
}
5.4 字符打印流
方法名 | 说明 |
---|
PrintWriter(String fileName) | 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新 |
PrintWriter(Writer out, boolean autoFlush) | 创建一个新的PrintWriter out:字符输出流 autoFlush: 一个布尔值,如果为真,则println , printf ,或format方法将刷新输出缓冲区 |
public class PrintWriterDemo {
public static void main(String[] args) throws IOException {
PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\pw.txt"),true);
pw.println("hello");
pw.println("world");
pw.close();
}
}
5.5 复制Java文件打印流改进版
- 案例需求
把模块目录下的 PrintStreamDemo.java 复制到模块目录下的 Copy.java - 分析步骤
- 根据数据源创建字符输入流对象
- 根据目的地创建字符输出流对象
- 读写数据,复制文件
- 释放资源
- 代码实现
public class CopyJavaDemo {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("myOtherStream\\PrintStreamDemo.java"));
PrintWriter pw = new PrintWriter(new FileWriter("myOtherStream\\Copy.java"),true);
String line;
while ((line=br.readLine())!=null) {
pw.println(line);
}
pw.close();
br.close();
}
}
5.6 对象序列化流
- 对象序列化介绍
- 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
- 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
- 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
- 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
- 对象序列化流: ObjectOutputStream
- 将 Java对象的原始数据类型和图形写入OutputStream。 可以使用ObjectInputStream读取(重构)对象。 可以通过使用流的文件来实现对象的持久存储。 如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
- 构造方法
方法名 | 说明 |
---|
ObjectOutputStream(OutputStream out) | 创建一个写入指定的OutputStream的ObjectOutputStream |
方法名 | 说明 |
---|
void writeObject(Object obj) | 将指定的对象写入ObjectOutputStream |
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
测试类
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));
Student s = new Student("林青霞",30);
oos.writeObject(s);
oos.close();
}
}
- 注意事项
- 一个对象要想被序列化,该对象所属的类必须必须实现 Serializable 接口
- Serializable 是一个标记接口,实现该接口,不需要重写任何方法
5.7 对象反序列化流
- 对象反序列化流: ObjectInputStream
- ObjectInputStream 反序列化先前使用ObjectOutputStream编写的原始数据和对象
- 构造方法
方法名 | 说明 |
---|
ObjectInputStream(InputStream in) | 创建从指定的InputStream读取的ObjectInputStream |
方法名 | 说明 |
---|
Object readObject() | 从ObjectInputStream读取一个对象 |
public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException,ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));
Object obj = ois.readObject();
Student s = (Student) obj;
System.out.println(s.getName() + "," + s.getAge());
ois.close();
}
}
5.8 serialVersionUID&transient
- serialVersionUID
- 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
- 会出问题,会抛出 InvalidClassException异常
- 如果出问题了,如何解决呢?
- 重新序列化
- 给对象所属的类加一个 serialVersionUID(类的内容可改,序列号不会改)
- private static final long serialVersionUID = 42L;
- transient
- 如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
- 给该成员变量加 transient关键字修饰,该关键字标记的成员变量不参与序列化过程
- 示例代码
学生类
public class Student implements Serializable {
private static final long serialVersionUID = 42L;
private String name;
private transient int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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 class ObjectStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
read();
}
private static void read() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("myOtherStream\\oos.txt"));
Object obj = ois.readObject();
Student s = (Student) obj;
System.out.println(s.getName() + "," + s.getAge());
ois.close();
}
private static void write() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myOtherStream\\oos.txt"));
Student s = new Student("林青霞", 30);
oos.writeObject(s);
oos.close();
}
}