目录
1.File
1.1 File类概述和构造方法
File:它是文件和目录路径名的抽象表示
- 文件和目录是可以通过File封装成对象的
- 对于file而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的
方法 | 说明 |
File(String pathname) | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 |
File(String parent,String child) | 从父路径名字符串和子路径名字符串创建新的File实例 |
File(File parent,String child) | 从父抽象路径名和子路径名字符串创建新的File实例 |
import java.io.*;
public class FileDemo {
public static void main(String[]args) {
//第一种
File f1=new File("E:\\itcast\\test.txt");//E:\\itcast\\test.txt
System.out.println(f1);
//第二种
File f2=new File("E:\\itcast","test.txt");//E:\\itcast\\test.txt
System.out.println(f2);
//第三种
File f3=new File("E:\\itcast");
File f4=new File(f3,"test.txt");//E:\\itcast\\test.txt
}
}
1.2 File类创建功能
方法 | 说明 |
public boolean createNewFile() | 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件 |
public boolean mkdir() | 创建由此抽象路径名命名的目录 |
public boolean mkdirs() | 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录 |
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
//1.在E:\\itcast目录下创建一个文件Java.txt
File f1=new File("E:\\itcast\\Java.txt");
System.out.println(f1.createNewFile());
//2.在E:\\itcast目录下创建一个javase
File f2=new File("E:\\itcast\\JavaSE");
System.out.println(f2.mkdir());
//3.在E:\\itcast目录下创建一个多级目录javaWeb\\html
File f3=new File("E:\\itcast\\javaWeb\\html");
System.out.println(f3.mkdirs());
}
}
注意:
- createNewFile:创建新的文件
- mkdir:创建新的目录
- mkdirs:创建多级目录
- 不能根据名字判断是文件还是目录,要看具体的方法
- 无论创建文件还是目录,都不可以重名,如果有重名,创建失败返回false,没有就返回true
1.3 File类判断和获取功能
方法 | 说明 |
public boolean isDirectory() | 测试此抽象路径名表示的File是否为目录 |
public boolean isFile() | 测试此抽象路径名表示的File是否为文件 |
public boolean exists() | 测试此抽象路径名表示的File是否存在 |
public String getAbsolutePath() | 返回此抽象路径名的绝对路径名字符串 |
public String getPath() | 将此抽象路径名转换为路径名字符串 |
public String getName() | 返回由此抽象路径名表示的文件或目录的名称 |
public String[]list() | 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组 |
public File[] listFiles() | 返回此抽象路径名表示的目录中的文件和目录的File对象数组 |
1.4 File类删除功能
方法名 | 说明 |
public boolean delete() | 删除由此抽奖路径名表示的文件或者目录 |
绝对路径和相对路径的区别
- 绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件。例如:E:\\itcast\\java.txt相对路径:必须使用取自其他路径名的信息进行解释。例如:myFile\\Java.txt
删除目录时的注意事项:
- 如果一个目录中有内容(目录,文件),不能直接删除。应该先删除目录中的内容,最后才能删除目录
1.5 递归
递归概述:以编程的角度来看,递归指的是方法定义中调用方法本身的现象
递归解决问题的思路:
把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
递归解决问题要找到两个内容:
- 递归出口:否则会出现内存溢出A
- 递归规则:与原问题相似的规模较小的问题
遍历File
import java.io.*;
public class FileDemo {
public static void main(String[]args) {
//根据给定的路径创建一个File对象
File srcFile=new File("E:\\Learning Tools");
//调用方法
getAllFiles(srcFile);
}
//定义递归方法
public static void getAllFiles(File srcFile) {
//获取给定的File目录下所有文件或者目录的File数组
File[] fileArray=srcFile.listFiles();
if(fileArray!=null) {
for(File file:fileArray) {
//判断File对象是否为目录
if(file.isDirectory()) {
getAllFiles(file);
}else {
System.out.println(file.getAbsolutePath());
}
}
}
}
}
2.字节流
2.1 IO流概述和分类
IO流概述:
- IO:输入/输出(Input/Output)
- 流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
- IO流就是用来处理设备间数据传输问题的,常见的应用:文件复制,文件上传,文件下载
IO流分类
- 按照数据的流向
输入流:读数据
输出流:写数据
- 按照数据类型来分
字节流
字节输入流;字节输出流
字符流
字符输入流;字符输出流
一般来说,我们说IO流的分类是按照数据类型来分的
如果数据通过Window自带的记事本软件打开,我们还可以读里面的内容,就使用字符流
否则使用字节流。如果你不知道该使用哪种类型的流,就使用字节流
2.2 字节流写数据
字节流抽象基类
- InputStream:这个抽象类是表示字节输入流的所有类的超类
- OutputStream:这个抽象类是表示字节输出流的所有类的超类
- 子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream:文件输出流用于将数据写入File
FileOutputStream(String name):创建文件输出流以指定的名称写入文件(此时文件创建好了)
用FileOutputStream时抛出的异常是FileNotFoundException
write的异常抛出是IOException,而后者抛出的异常是前者的父类
void write(int :b)将指定的字节写入文件输出流
void close():释放资源
使用字节输出流写数据的步骤:
- 创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法
- 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
2.3 字节流写数据的三种方法
方法名 | 说明 |
void write(int b) | 将指定的字节写入此文件输出流,一次写一个字节数据(只写一个) |
void write(byte[]b) | 将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据(先创建数组再写入) |
void write(byte[]b,int off,int len) | 将len字节从指定的字节数组开始,从索引位置off开始写入此文件输出流一次写一个字节数组的部分数据 |
一个特殊的方法:byte[] getBytes();返回字符串对应的字节数组
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
FileOutputStream fos=new FileOutputStream("E:\\itcast\\test.txt");
/*做了三件事情:
* A:调用系统功能创建了文件
* B:创建了字节输出流对象
* C:让字节输出流对象指向创建好的文件*/
byte[] bys="wykbd2022".getBytes();
fos.write(bys);
//最后都要释放资源
fos.close();
}
}
2.4 字节流写数据的两个小问题
字节流写数据实现换行
- 写完数据后,加换行符
windows:\r\n
linux:\n
mac:\r
字节流写数据实现追加写入
- publicFileOutputStream(Stringname,boolean append)
- 创建文件输出流以指定的名称写入文件。如果第二个参数为tue,则字节将写入文件的未尾而不是开头
2.5 字节流写数据加异常处理
finally:在异常处理时提供finally块来执行所有清除操作。比如说I0流中的释放资源
特点:被finally控制的语句一定会执行,除非IVM退出
try{
可能出现异常的代码
}catch(异常类名 变量名){
异常处理的代码
}finally{
执行所有清除操作
}
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
FileOutputStream fos=null;//先对fos初始化
try {
//直接对fos进行赋值
fos=new FileOutputStream("myGame\\fos.txt");
fos.write("hello".getBytes());
}catch(IOException e) {
e.printStackTrace();
}finally {
try {
//假如try里的内容有误,fos则会为null,进而会出现空指针异常的情况,故需要添加if来判断
if(fos!=null) {
fos.close();
}
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
2.6 字节流读数据
标准示例代码:
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
FileInputStream fis=new FileInputStream("E:\\itcast\\test.txt");
int by;
while((by=fis.read())!=-1) {
System.out.print((char)by);
}
}
}
2.6.1 案例(一次读一个字节数据)
复制文本文件:
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
/*
* 从文件中读出来,再写到另一个文件中
*
* 数据源:E:\\itcast\\test.txt
* 目的地:E:\\itcast\\fos.txt
* 思路:
1.根据数据源创建字节输入流对象
2.根据目的地创建字节输出流对象
3.读写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
4.释放资源
* */
FileInputStream fis=new FileInputStream("E:\\itcast\\test.txt");
FileOutputStream fos=new FileOutputStream("E:\\itcast\\fox.txt");
int by;
while((by=fis.read())!=-1) {
fos.write(by);;
}
fos.close();
fis.close();
}
}
2.6.2 案例(一次读一个字节数组数据)
需求:把文件fox.txt中的内容在控制台输出、
//String的构造方法将Byte数组转换为字符串
new String(变量名,0,len)
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
FileInputStream fis=new FileInputStream("E:\\itcast\\test.txt");
byte[]bys=new byte[1024];//1024的整数倍
int len;
while((len=fis.read(bys))!=-1) {
//String的构造方法将Byte数组转换为字符串
System.out.print(new String(bys,0,len));
}
fis.close();
}
}
注意:当读完后输出的是-1,所以让判断条件不等于-1而不是不等于0
错误代码:
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
FileInputStream fis=new FileInputStream("E:\\itcast\\test.txt");
byte[]bys=new byte[1024];//1024的整数倍
int len;
while((len=fis.read(bys))!=0) {
//String的构造方法将Byte数组转换为字符串
System.out.print(new String(bys,0,len));
}
fis.close();
}
}
运行结果:
2.7 字节缓冲流
字节缓冲流:
- BufferedOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
- BufferedlnputStream:创建BufferedlnputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
构造方法:
- 字节缓冲输出流:BufferedOutputStream(OutputStream out)
- 字节缓冲输入流:BufferedInputStream(InputStream in)
- 字节缓冲流仅仅提供缓冲区而真正的读写数据还得依算基本的字节流对象进行操作
例如:
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("E:\\itcast\\bos.txt"));
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
bos.close();
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("E:\\itcast\\bos.txt"));
/*int by;
while((by=bis.read())!=-1) {
System.out.print((char)by);
}*/
byte[] bys=new byte[1024];
int len;
while((len=bis.read(bys))!=-1) {
System.out.print(new String(bys,0,len));
}
bis.close();
}
}
/*
*hello
*world
*/
注意:字节缓冲流一次读写一个字节数组是最快的即(buffered+byte[])
3.字符流
3.1 为什么出现字符流
由于字节流操作中文不是特别的方便,所ava就提供字符流
- 字符流=字节流 +编码表
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接成中文
- 汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数
3.2 编码表
基础知识:
- 计算机中储存的信息都是用二进制数表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果
- 按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制教按照某种规则解析显示出来,称为解码。这里强调一下:按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号。否则就会导致乱码现象
字符编码:就是一套自然语言的字符与二进制数之间的对应规则(A,65)
字符集:
- 是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
- 计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
ASCII字符集:
- ASCll(American Standard Code for Information Interchange,美国信息交换标准代码):是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)
- 基本的ASCI1字符集,使用7位表示一个字符,共128字符。ASCI的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等
GBXXX字符集:
- GB2312:简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外教学符号、罗马希腊的字母、日文的假名等都编进去了,连在ASCI里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的“全角"字符,而原来在127号以下的那些就叫"半角"字符了
- GBK:最常用的中文码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等
- GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等
Unicode字符集:
- 为表达任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。它最多使用4个字节的数字来表达每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF32。最为常用的UTF-8编码
- UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码
编码规则:
1.128个US-ASCII字符,只需一个字节编码
2.拉丁文等字符,需要二个字节编码
3.大部分常用字(含中文),使用三个字节编码
4.其他极少使用的Unicode辅助字符,使用四字节编码
总结:无论采用哪种规则的编码,就要采用对应的规则解码,否则会出现乱码
3.3字符串中的编码解码问题
编码:
- byte[] getBytes():使用平台的默认字符集将该 String编码为一系列字节,将结果存储到新的字节数组中
- byte[] getBytes(String charsetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
解码:
- String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
- String(byte[] bytes,String charsetName):通过指定的字符集解码指定的字节数组来构造新的 String
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class FileDemo {
public static void main(String[]args) throws UnsupportedEncodingException {
String s="中国";
byte[] bys=s.getBytes("UTF-8");
System.out.println(Arrays.toString(bys));
byte[] byss=s.getBytes();//GBK编码
System.out.println(Arrays.toString(byss));
String str=new String(byss);//GBK解码
System.out.println(str);
String str2=new String(bys,"UTF-8");
System.out.println(str2);
}
}
/*运行结果:
[-28, -72, -83, -27, -101, -67]
[-42, -48, -71, -6]
中国
中国
* */
3.4 字符流中的解码编码问题
InputStreamReader:是从字节到字符流的桥梁
- 它读取字节,并使用指定的缩码将其解码为字符
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
0utputStreamWriter:是从字符流到字节流的桥粱
- 是从字符流到字节流的桥梁,使用指定的编码将写入的字符编码为字节
- 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集
3.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() | 刷新流,还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据 |
实际操作使用格式:(注意释放资源先刷新在关闭)
import java.io.*;
public class FileDemo {
public static void main(String[]args) throws IOException {
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream( "E:\\itcast\\Java.txt"));
//void write(int c):写一个字符
osw.write(97);
//void flush():刷新流
osw.flush();
osw.write(98);
osw.flush();
osw.write(99);
osw.flush();
//void write(char[]cbuf):写入一个字符数组
char[] chs ={'a','b','c','d','e'};
osw.write(chs);
osw.flush();
//void write(char[]cbuf,int off,int len):写入字符数组的一部分
osw.write(chs,0,chs.length);
osw.write(chs,1,3);
osw.flush();
//void write(String str):写一个字符串
osw.write( "abcde");
osw.write( "abcde",0,"abcde".length());
osw.close();
}
}
3.6 字符流读数据的2种方式
方法名 | 说明 |
int read() | 一次读一个字符数据 |
int read(char[] cbuf) | 一次读一个字符数组数据 |
InputStreamReader isr=new InputStreamReader(new FileInputStream("......"));
char[]chs = new char[1024];
int len;
while((len=isr.read(chs))!=-1)
{
System.out.print(new String(chs,0,len));
}
3.7案例
3.7.1复制Java文件
需求:把模块目录下的“ConversionStreamDemo,java”复制到模块目录下的“Copyjava"
import java.io.*;
public class CopyJava {
public static void main(String[]args) throws IOException{
InputStreamReader isr=new InputStreamReader(new FileInputStream("D:\\program files(x86)\\Java\\MyCharStream\\ConversionStreamDemo.java"));
//根据目的地创建字符输出对象
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("D:\\program files(x86)\\Java\\MyCharStream\\Copy.java"));
//读写数据
int ch;
while((ch=isr.read())!=-1) {
osw.write(ch);
}
osw.close();
isr.close();
}
}
3.7.2复制Java文件(改进)
需求:把模块目录下的“ConversionStreamDemo,java”复制到模块目录下的“Copyjava"
分析:
① 转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化书写,转换流提供了对应的子类
②)FileReader:用于读取字符文件的便捷类
FileReader(String fileName)
③FileWriter:用于写入字符文件的便捷类
FileWriter(String fileName)
④)数据源和目的地的分析
数据源:myCharStream\ConversionStreamDemo,java---读数据 --- Reader ---InputStreamReader ---FileReader
目的地:myCharStream\\Copy,java---写数据---Writer---OutputStreamWriter ---FileWriter
import java.io.*;
public class CopyJava {
public static void main(String[]args) throws IOException{
FileReader fr=new FileReader("D:\\program files(x86)\\Java\\MyCharStream\\ConversionStreamDemo.java");
FileWriter fw=new FileWriter("D:\\program files(x86)\\Java\\MyCharStream\\Copy.java");
char[]ch=new char[1024];
int len;
while((len=fr.read(ch))!=-1) {
fw.write(ch,0,len);
}
fw.close();
fr.close();
}
}
3.8 字符缓冲流(2.7)
字符缓冲流:
- BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
- BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途
构造方法:
- BufferedWriter(Writer out)
- BufferedReader(Reader in)
import java.io.*;
public class CopyJava {
public static void main(String[]args) throws IOException{
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\itcast\\bw.txt"));
bw.write("aaaaaa\r\n");
bw.write("bbbbbb");
bw.close();
BufferedReader br=new BufferedReader(new FileReader("E:\\itcast\\bw.txt"));
char[] ch=new char[1024];
int len;
while((len=br.read(ch))!=-1) {
System.out.print(new String(ch,0,len));
}
br.close();
}
}
3.9字符缓冲流特有的功能
BufferedWriter:
- void newLine():写一行行分隔符行分隔符字符串由系统属性定义
BufferedReader:
- public String readLine():读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null
具体使用案例:
import java.io.*;
public class CopyJava {
public static void main(String[]args) throws IOException{
BufferedWriter bw=new BufferedWriter(new FileWriter("E:\\itcast\\bww.txt"));
for(int i=0;i<10;i++) {
bw.write("00"+i+"号");
bw.newLine();
bw.close();//三件套
}
bw.close();
BufferedReader br=new BufferedReader(new FileReader("E:\\itcast\\bww.txt"));
String line;
while((line=br.readLine())!=null) {
System.out.println(line);
}
br.close();
}
}
/*结果
000号
001号
002号
003号
004号
005号
006号
007号
008号
009号
*/
小结:
3.10案例
3.10.1复制单级文件夹
import java.io.*;
public class CopyJava {
public static void main(String[]args) throws IOException{
//创建数据源对象
File srcFolder=new File("E:\\itcast");
//获取数据源目录File对象的名字
String srcFolerName=srcFolder.getName();
//创建目的地目录File对象
File destFolder=new File("D:\\program files(x86)\\Java\\MyCharStream",srcFolerName);
//判断目的地下是否有File存在,不存在就创建
if(!destFolder.exists()) {
destFolder.mkdir();
}
//获得数据源下目录下所有文件的File数组
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[2048];
int len;
while((len=bis.read(bys))!=-1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
}
3.10.2复制多级文件夹
思路:
- 创建数据源File对象,路径是E:\itcast
- 创建目的地File对象,路径是F:\
- 写方法实现文件夹的复制,参数为数据源File对象和目的地File对象
- 判断数据源File是否是目录
是:
A:在目的地下创建和数据源File名称一样的目录
B:获取数据源File下所有文件或者目录的File数组
C:遍历该File数组,得到每一个File对象
D:把该File作为数据源File对象,递归调用复制文件夹的方法
不是:说明是文件,直接复制,用字节流
import java.io.*;
public class CopyJava {
public static void main(String[]args) throws IOException{
//创建数据源对象
File srcFile=new File("E:\\itcast");
//获取数据源目录File对象的名字
File destFile=new File("D:\\program files(x86)\\Java\\MyCharStream");
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[2048];
int len;
while((len=bis.read(bys))!=-1) {
bos.write(bys,0,len);
}
bos.close();
bis.close();
}
}
3.11 复制文件的异常处理
try...catch...finally:
try{
可能出现的异常
}catch(异常类名 变量名){
异常处理的代码
}finally{
执行所有清楚操作
}
public static void main(String[]args){
FileInputStream fis=null;
FileOutputStream fos=null;
try{
fis=new FileInputStream("E:\\itcast\\test.txt");
fos=new FileOutputStream("E:\\itcast\\fox.txt");
int by;
while((by=fis.read())!=-1) {
fos.write(by);;
}
fos.close();
fis.close();
}catch(IOException e) {
e.printStackTrace();
}finally {
if(fos!=null) {
try {
fos.close();
}catch(IOException e) {
e.printStackTrace();
}
}
if(fis!=null) {
try {
fis.close();
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
JDK7改进方案:
try(定义流对象){
可能出现的代码
}catch(异常类名 变量名){
异常处理代码
}//自动释放资源
public static void main(String[]args){
try(FileInputStream fis=new FileInputStream("E:\\itcast\\test.txt");
FileOutputStream fos=new FileOutputStream("E:\\itcast\\fox.txt");){
int by;
while((by=fis.read())!=-1) {
fos.write(by);;
}
}catch(IOException e) {
e.printStackTrace();
}
}
JDK9改进方案:
定义输入流对象;
定义输出流对象;
try(输入流对象;输出流对象){
可能出现异常的代码;
} catch(异常类名 变量名){
异常处理的代码;
}//自动释放资源
public static void main(String[]args)throws IOException{
FileInputStream fis=new FileInputStream("E:\\itcast\\test.txt");
FileOutputStream fos=new FileOutputStream("E:\\itcast\\fox.txt");
try(fis;fos){
int by;
while((by=fis.read())!=-1) {
fos.write(by);;
}
}catch(IOException e) {
e.printStackTrace();
}
}
4.特殊操作流
4.1标准输入输出流
System类中有两个静态的成员变量:
- public static final InputStream in:标准输入流。通常该流对应于键盘输入或由主机环境或用户指定的另一个输入源
- public static final PrintStream out:标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
自己实现键盘录入数据:
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
写起来太麻烦,Java就提供了一个类实现键盘录入
- Scanner sc =new Scanner(System.in);
输出语句的本质:是一个标准的输出流
- PrintStream ps = System.out;
PrintStream类有的方法,System.out都可以使用
4.2 打印流
打印流分类:
- 字节打印流:PrintStream
- 字符打印流:PrintWriter
打印流的特点:
- 只负责输出数据,不负责读取数据
- 有自己的特有方法
字节打印流
- PrintStream(String fileName):使用指定的文件名创建新的打印流
- 使用集成父类的方法写数据,查看时会转码;使用自己特有的方法写数据,查看的数据原样输出
字符打印流
字符打印流PrintWriter的构造方法
方法名 | 说明 |
PrintWriter(String fileName) | 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行刷新 |
PrintWriter(Writer out,boolean autoFlush) | 创建一个新的PrintWriter out:字符流输出 autoFlush:一个布尔值,如果为真,则println,printf,或者format方法将刷新输出缓冲区 |
第二个构造方法的使用
public static void main(String[]args) throws IOException {
PrintWriter pw=new PrintWriter(new FileWriter("E:\\itcast\\pw.txt"),true);
pw.println(123);
}
案例改进:
Java文件复制
public static void main(String[]args) throws IOException {
//根据数据源创建字符输入流对象
BufferedReader br = new BufferedReader(new
FileReader("myOtherstream\\PrintstreamDemo.iava"));
//根据目的地创建字符输出流对象
PrintWriter pw = new PrintWriter(new FileWriter( "myOtherstream\\copy.java"), true);
//读写数据,复制文件
String line;
while((line=br.readLine())!=null){
pw.println(line);
}
//释放资源
pw.close();
br.close();
}
4.3 对象序列化流
1.对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的教据和对象中存储的属性等信息字节序列写到文件之后,相当于文件中持久保存了一个对象的信息反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
要实现序列化和反序列化就要使用对象序列化流和对象反序列化流:
- 对象序列化流:ObjectOutputStream
- 对象反序列化流:ObjectInputStream
2.对象序列化流:ObjectOutputStream
将Java对象的原始数据类型和图形写入OutputStream。可以使用ObjectlnputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
构造方法:
- ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream的ObjectOutputStream
序列化对象的方法:
- void writeObject(Object obj):将指定的对象写入ObjectOutputStream
用法
public static void main(String[]args) throws IOException{
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("...\\..."));
Student s=new Student("abc",98,100);
oos.writeObject(s);
oos.close();
}
public class Student implements Seriaizable {
private String name;
private int Chinese;
private int English;
public Student() {}
public Student(String name,int Chinese,int English) {
this.name=name;
this.Chinese=Chinese;
this.English=English;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
public void setChinese(int Chinese) {
this.Chinese=Chinese;
}
public int getChinese() {
return Chinese;
}
public void setEnglish(int English) {
this.English=English;
}
public int getEnglish() {
return English;
}
}
3.对象反序列化流:ObjectlnputStream
- ObjectlnputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象
构造方法:
- ObjectInputStream(InputStream in):创建从指定的InputStream读取的ObjectInputStream
反序列化对象的方法:
- ObjectreadObject():从ObjectlnputStream读取一个对象
用法
public static void main(String[]args) throws IOException,ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("...\\..."));
//Object readObject():从ObjectInputStream读取一个对象
Object obj=ois.readObject();
Student s=(Student) obj;
System.out.println(s.getName()+","+s.getAge());
ois.close();
}
4.用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
- 会出问题,抛出InvalidClassException异常
如果出问题了,如何解决呢?
- 给对象所属的类加一个seriaIVersionUID
- private static final long serialVersionUlD = 42L;
如果一个对象中的某个成员变量的值不想被序列化,又该如何实现呢?
- 给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程
4.4Properties
1.Properties概述:
- 是一个Map体系的集合类
- Properties可以保存到流中或从流中加载
2.用法
public class MapTest {
public static void main(String[] args) {
Properties prop=new Properties();
prop.put("001", "a");
prop.put("002", "b");
prop.put("003", "c");
Set<Object> keySet=prop.keySet();
for(Object key:keySet) {
Object value=prop.get(key);
System.out.println(key+","+value);
}
}
}
3.Properties作为集合的特有方法
方法 | 说明 |
Object setProperty(String key,String value) | 设置集合的键和值,都是String类型的,底层调用Hashtable方法put |
String getProperty(String key) | 使用此属性列表中指定的键搜索属性 |
Set<String> stringPropertyNames() | 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 |
用法:
import java.util.*;
public class MapTest {
public static void main(String[] args) {
Properties prop=new Properties();
prop.setProperty("001", "a");
prop.setProperty("002", "b");
prop.setProperty("003", "c");
Set<String> names=prop.stringPropertyNames();
for(String key:names) {
String value=prop.getProperty(key);
System.out.println(key+","+value);
}
}
}
4.Properties和IO流结合的方法
方法名 | 说明 |
void load(InputStream inStream) | 从输入字节流读取属性列表(键和元素对) |
void load(Reader reader) | 从输入字符流读取属性列表(键和元素对) |
void store(OutputStream out,String comments) | 将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流 |
void store(Writer write,String comments) | 将此属性列表(键和元素对)写入此Properties表中,以适合使用load(Reader)方法的格式写入输出字符流 |
使用:
import java.io.*;
import java.util.*;
public class Test {
public static void main(String[] args) throws IOException {
myStore();//把集合中的数据保存到文件
myLoad();//把文件中的数据加载到集合
}
private static void myLoad() throws IOException {
// TODO Auto-generated method stub
Properties prop=new Properties();
FileReader fr=new FileReader("E:\\itcast\\fw.txt");
prop.load(fr);
System.out.println(prop);
}
private static void myStore()throws IOException {
// TODO Auto-generated method stub
Properties prop=new Properties();
prop.setProperty("001", "a");
prop.setProperty("002", "b");
prop.setProperty("003", "c");
prop.setProperty("004", "d");
FileWriter fw=new FileWriter("E:\\itcast\\fw.txt");
prop.store(fw, null);
fw.close();
}
}
4.5案例
需求:请写出小程序实现猜数字小游戏,只能玩三次,如果还想玩,提示:游戏试玩已结束,想玩请充值(www.itcast.cn)
思路:
① 写一个游戏类,里面有一个猜数字的小游戏
② 写一个测试类,测试类中有main()方法,main()方法中按照下面步骤完成:
A:从文件中读取数据到Properties集合,用load()方法实现
文件已经存在:game.txt
里面有一个数据值:count=0
B:通过Properties集合获取到玩游戏的次数
C:判断次数是否到到3次了
如果到了,给出提示:游戏试玩已结束,想玩请充值(www.itcast.cn)
如果不到3次:
玩游戏
次数+1,重新写回文件,用Properties的store()方法实现
//猜数字游戏类
import java.util.*;
public class GuessNumber {
private GuessNumber() {}
public static void start() {
Random r=new Random();
int num=r.nextInt(100)+1;
while(true) {
System.out.println("请输入你的数值");
Scanner sc=new Scanner(System.in);
int GuessNumber=sc.nextInt();
if(GuessNumber>num) {
System.out.println("你输入的数值偏大,请重新输入:");
}else if(GuessNumber<num) {
System.out.println("你输入的数值偏小,请重新输入");
}else {
System.out.println("恭喜你猜对了!");
break;
}
}
}
}
//测试类
import java.util.*;
import java.io.*;
public class PropertiesTest {
public static void main(String[]args)throws IOException{
Properties prop=new Properties();
FileReader fr=new FileReader("E:\\itcast\\Game.txt");
prop.load(fr);
fr.close();
String count=prop.getProperty("count");
int number=Integer.parseInt(count);
if(number>=3) {
System.out.println("游戏试玩结束,想玩请充值(www.itcast.cn)");
}else {
GuessNumber.start();
number++;
prop.setProperty("count", String.valueOf(number));
FileWriter fw=new FileWriter("E:\\itcast\\Game.txt");
prop.store(fw, null);
fw.close();
}
}
}