1 异常
1.1 异常种类
(1) Error// 编码阶段提示,不修正则无法通过编译
(2) Exception// 编码阶段不提示,运行时发现
1.2 异常处理
异常信息必须try catch捕获处理,或者throws向上抛出
1.2.1 捕获异常
注释:finally执行时会缓存try或catch中的return数据,等待finally执行结束将其返回,如果finally中有return则会覆盖掉缓存的return值,最终返回finally的return数据。
java
public void fn() {
try {
处理... // throw new Exception();
} catch (Exception e) {
异常处理代码... // 注释:异常时,catch中的return覆盖try中的return值返回。
} finally {
终止时运行代码...
}
}
1.2.2 抛出异常
java
public void fn() throws Exception{
处理... // throw new Exception();
}
1.2.3 RuntimeException
注释:throw RuntimeException 外层不try catch 也可不做任何处理
java
public void fn() {
处理... // throw new RuntimeException();
}
2 文件File
2.1 创建
(1) 创建文件对象:File file = new File("D:\\test\\test.txt"); // 可以用/路径
(2) 创建文件:file.createNewFile();
(3) 创建文件夹对象:File file = new File("D:\\test\\test\\"); // 可以以\\结束,或文件夹名结束
(4) 创建单个文件夹:file.mkDir();
(5) 创建多个文件夹:file.mkDris();
2.2 判断
(1) 判断文件(夹)存在:file.exists()
(2) 判断是否为文件:file.isFile()
(3) 判断是否为文件夹:file.isDirectory()
(4) 判断是否可读取:file.canRead()
(5) 判断是否可写入:file.canWrite()
2.3 获取属性
(1) 取文件名(含后缀):file.getName()
(2) 全文件名(含路径及后缀):file.getAbsolutePath()
(3) 获取文件列表:File\[\] files = file.listFile(); //无访问权限返回null, 空文件夹返回空数组
(4) 获取文件名列表:String\[\] fileNames = file.list()
(5) 获取父级文件夹名:String parentName = file.getParent();
(6) 获取父级文件夹:File parentFile = file.getParentFile();
2.4 其它
(1) 重命名:file.renameTo(File)
(2) 删除:file.delete() // 删除文件或空文件夹
3 IO流
按流向分:输入流,输出流 // 输入流(Java读取数据),输出流(Java写出数据)
按方式分:字节流,字符流 // 字节流(处理所有类型,文本,音视频,图片),字符流(处理文本信息)
字节输入流:InputStream(抽象类),字节输出流:OutputStream(抽象类)
字符输入流:Reader(抽象类),字符输出流:Writer(抽象类)
换行符:Windows("/r/n"),Linux("/n") // 回车换行,java会将 /r 或 /n 字段补齐,尽量写全
3.1 字节流
(1) 文件字节输入流:FileInputStream
注释:只适合做文件复制,不适合处理字符串数据,读取中文会截断文字导致乱码(可通过一次读取全部数据解决)bytef.length 或 byte\[\] b = f.readAllBytes(); 但是文件太大会内存溢出。
java
// 一个字节一个字节读取
FileInputStream fis = new FileInputStream(File | fileName); // 创建流
int b;
while( (b=fis.read()) != -1) { // 读取一个字节,读到-1结束
// 可以用(char)b;强转 输出字节
}
fis.close();
java
// 读取字节数组
FileInputStream fis = new FileInputStream(File | fileName); // 创建流
byte[] b = new byte[1024];
int len;
while( (len=fis.read(b)) != -1) { // 读取数组长度的字节(重点:最后的读取不清空数组后面数据)
String str = new String(b, 0, len); // 根据读取长度重新new字符串查看
}
fis.close();
(2) 文件字节输出流:FileOutputStream
java
FileOutputStream fos = new FileOutputStream(File | fileName [, boolean])
// true追加内容,false覆盖(默认)
// 存在文件清空,无文件新建,无文件夹报错
fos.write(int); // 写出1个字节(ASCII)
fos.write(byte[]); // 写出一个数组(可用str.getBytes()获取数组)
fos.write(byte[], 开始下标, 长度); // 按下标长度写出数组
注释:写出换行符【fos.write("\r\n".getBytes())】
(3) 关闭流
java
// JDK7之前
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(fileName); // 输入流
fos = new FileOutputStream(fileName); // 输出流
} catch (Exception e) {
} finally {
// 如果不关闭流文件会锁住
if (fis != null) {
try {
fis.close
} catch (IOException e) {
}
}
if(fos != null) {
try {
fos.close
} catch (IOException e) {
}
}
}
java
// JDK7
try (FileInputStream fis = new FileInputStram(file);
FileOutputStream fos = new FileOutputStream(file);) {
// 括号中只能写实现了AutoCloseable接口的对象
} catch (Exception e) {
}
// 不用写finally关闭流,自动关闭
java
// JDK9
FileInputStream fis = new FileInputStram(file);
FileOutputStream fos = new FileOutputStream(file);
try (fis; fos) {
} catch (Exception e) {
}
3.2 字符流
注释:字符流用来读写文件内容,自带1024*8个字节的缓冲区内存
(1) 文件字符输入流:FileReader
// 读1024*8个字节到缓冲区内存,有内存读内存数据,没有内存读文件到缓冲区。
java
// 一个字符一个字符读取
FileReader fr = new FileReader(File | fileName); // 文件不存在会报错
int ch;
while (( ch = fr.read() ) != -1) { // 读取一个英文或一个中文,返回中文或英文十进制数值,-1结束
(char)ch;
}
java
// 读取字符数组
FileReader fr = new FileReader(File | fileName); // 文件不存在会报错
char[] chs = new char[1024];
int len;
while(( len = fr.read(chs) ) != -1) { // 将数据读到字符数组里
String str = new String(chs, 0, len);
}
(2) 文件字符输出流:FileWriter
// 写入缓冲区,写满自动写入文件,或者手动flush或close
java
FileWriter fw = new FileWriter(File | fileName [,boolean]);
//true追加内容,false覆盖(默认)
// 文件存在则对其清空,不存在则创建,没有文件夹报错
fw.write(int);
fw.write(char[] [,开始下标, 长度])
fw.write(String [,开始下标, 长度])
fw.flush(); // 字符流写出结束后必须刷出,或者关闭
3.3 缓冲流
注释:自带8kb缓冲区(8192)大小
效率:缓冲流数组 > (缓冲流字节 = 基本流数组) > 基本流字节。数组越大提升越小(最优 1024*32)
(1) 字节输入缓冲流:BufferedInputStream
java
BufferedInputStream bis = new BufferedInputStream(InputStream);
int b;
while( (b=bis.read()) != -1) { // 读一个字节
}
java
BufferedInputStream bis = new BufferedInputStream(InputStream);
byte[] b = new byte[1024];
int len;
while( (len=bis.read(b)) != -1) {
String str = new String(b, 0, len);
}
(2) 字节输出缓冲流:BufferedOutputStream
java
BufferedOutputStream bos = new BufferedOutputStream(InputStream);
bos.write(int); // 写出1个字节
bos.write(byte[]);// 写出一个数组
bos.write(byte[], 开始下标, 长度); // 按下标长度写出数组
(3) 字符输入缓冲流:BufferedReader
// 基本字符流自带缓冲区,缓冲存流提升不明显。文件编码与程序编码一致,br读文件才不会乱码
java
BufferedReader br = new BufferedReader(Reader [, int]); //可指定缓冲区大小,关闭时只关br即可
char[] chs = new char[1024];
int len;
while((len = br.read(chs)) != -1) {
String str = new String(chs, 0, len);
}
java
BufferedReader br = new BufferedReader(Reader [, int]);
String line;
while((line = br.readLine()) != null) { // 没有数据返回null,不会读取到回车换行符
String str = line;
}
(4) 字符输出缓冲流:BufferedWriter
java
BufferedWriter bw = new BufferedWriter(Writer); // 开启追加文本模式在Writer构造器指定
bw.write(97 | char | String); // 写int输出char
bw.newLine(); // 换行输出(跨平台换行)
3.4 转换流
注释:JDK11将其淘汰了,当字节流需要使用字符流方法时使用。
(1) 字符输入转换流:InputStreamReader
解决BuifferedReader文件与程序编码不一致的乱码问题
java
InputStreamReader isr = new InputStreamReader(InputStream, ["字符集"])
// 字节流转成字符流读取
BufferedReader br = new BufferedReader(isr);
(2) 字符输出转换流:OutputStreamWriter
注释:也可使用 byte\[\] bytes = str.getBytes(字符集)方法获取指定字符集的字符串二进制数据
java
OutputStreamWriter osw = new OutputStreamWriter(OutputStream, ["字符集"])
// 字符流转成字节流输出
BufferedWriter bw = new BufferedWriter(osw);
(3) JDK11替代方案:FileReader, FileWriter
java
FileReader fr = new FileReader(File, Charset.forName("GBK"))
FileWriter fw = new FileWriter(File, Charset.forName("GBK"))
3.5 打印流
注释:以字节或字符形式输出文本
(1) 字节输出打印流:PrintStream
java
PrintStream ps = new PrintStream(OutputStream [,字符集]);// Charset.forName("...")
ps.write(97); // 输出a
ps.print(97); // 输出97, println换行输出
ps.printf("%sxxx%s", "参1", "参2"); // 占位符输出(参1xxx参2)
// %s字符串占位,%n换行,%b布尔,%d十进制, %x十六进制,%o八进制,%f小数
(2) 字符输出打印流:PrintWriter
java
PrintWriter pw = new PrintWriter(Writer)
pw.write(97); // 输出a
pw.print(97); // 输出97
pw.println(97); // 换行输出,自动刷新
3.6 数据流
注释:目的是存储数据,不是人为观看用的
(1) 数据输入流:DataInputStream
java
DataInputStream dis = new DataInputStream(InputStream)
dis.write基本类型(数据); // 可输出多次相同类型
dis.writeUTF(str);
(2) 数据输出流:DataOutputStream
java
DataOutputStream dos = new DataOutputStream(OutputStream)
dos.read基本类型(); // 可读取多次相同类型
dos.readUTF();
3.7 序列化流
注释:写入写出对象数据
(1) 序列化流:ObjectOutputStream
java
ObjectOutputStream oos = new ObjectOutputStream(OutputStream)
oos.write基本类型(数据);
oos.writeObject(对象); // 写出的文件看不懂,类似于加密
(2) 反序列化流:ObjectInputStream
java
ObjectInputStream dis = new ObjectInputStream(InputStream)
类 对象 = (类) dis.readObject();
注释:序列化对象类需要实现 Serizlizable接口,对象中不定义版本号(默认版本号)每次修改文件会发生改变,导致返序列号失败,可手动追加版本号(private static final long serialversionuid= 1l;),序列化多个对象用 ArrayList,不序列化某个属性(private transientString 属性;)
3.8 压缩流
(java.util.zip)
(1) 压缩流:
java
// 单文件压缩
File fileTo = new File("D:/xx/", "out.zip"); // 目标压缩文件名
FileOutputStream fos = new FileOutputStream(fileTo);
ZipOutputStream zip = new ZipOutputStream(fos);
ZipEntry ze = new ZipEntry("xx/xx/text.txt"); // 压缩文件内容层级
zip.putNextEntry(ze);
File fileFrom = new File("D;/xx/test.txt"); // 原文件
FileInputStream fis = new FileInputStream(fileFrom);
int b; while((b=fis.read()) != -1) { zip.write(b); } // 读原文件压缩
zip.closeEntry();
zip.close();
java
// 多文件压缩
File fileTo = new File("D:/xx/", "out.zip");
FileOutputStream fos = new FileOutputStream(fileTo);
ZipOutputStream zip = new ZipOutputStream(fos);
File fileFrom = new File("D;/xx");
File[] files = ff.listFiles();
for(File file : files) {
if (file.isFile()) { // 只输出文件,不输出空文件夹
ZipEntry ze = new ZipEntry(path+"/"+file.getName());
zip.putNextEntry(ze);
FileInputStream fis = new FileInputStream(file);
int b; while((b=fis.read()) != -1) { zip.write(b);}
fis.close();
zip.closeEntry();
} else {
// 递归调用当前方法
}
}
4 编码格式
4.1 字符集与编码格式
ANSI(随系统,中文系统默认GBK)
GBK:将两个字节转成10进制再查询汉字(字节1开头是中文,占用2个字节。字节0开头是英文,占用2个字节)
Unicode:统一字符集(UTF-8 是可变长编码格式,不是字符集(1-4字节),中文3字节(110+10两字节拉丁文,1110+10+10三字节中文,11110+10+10+10四个字节))
4.2 乱码
注释:不能用字节流读文本,会显示乱码(可以用来复制文件,因为字节没有丢失)
IDEA(默认UTF-8):不同编码str.getBytes()读到的字节不一样
Eclipse(默认GBK):不同编码str.getBytes()读到的字节不一样
java
String str1 = new String(bytes[], [charsetName]); // 指定字符集获取文本
str2.getBytes(charsetName); // 指定字符集或取字节(gbk, iso8859-1,...)
5 实用案例
5.1 文件复制
5.1.1 基本流
java
FileInputStream fis = new FileInputStream("xx.mp4"); // 读取文件流
FileOutputStream fos = new FileOutputStream("xxCopy.mp4"); // 写出文件流
int b; while((b=fis.read())!=-1){fos.write(b); } // 将读取内容复制写出
// 基本流最慢,缓冲流读1字节第二慢,基本流按数组读和缓冲流数组读最快(差别不大)
5.1.2 commons-io
Apache提供
java
FileUtils.copyFile(f1, f2); // 复制文件
FileUtils.copyDirectory(dir1, dir2); // 复制文件夹
FileUtils.readFileToString(); // 读数据
FileUtils.writeStringToFile(str); // 写数据
5.2 文件上传
5.2.1 前端上传文件
html
<form method="post" encType="multipart/form-data"> 以多段拼接二进制发送服务器
<input type="file" />
</form>
5.2.2 后端获取上传的文件
(1) Servlet3.0注解
java
@multipartConfig( // 标识servlet支持文件上传
location="xxx" // 临时存文件目录
maxFileSize=long // 传文件最大字节
maxRequestSize=long // 整个请求最大字节
fileSizeThreshold=int // 文件大于指定值,存入磁盘
)
public class XxServlet {
public void doPost(...) {
// getParameter获取标签内容
// 获取文件:
Part part = request.getPart("文件标签name");
String fileName = part.getSubmittedFilename();
part.write(path + fileName); // 文件上传到指定路径
}
}
(2) Servlet读取
java
ServletInputStream si = req.getInputStream();// 获取文件流
byte [] bytes = new bytes[1024];
si.read(bytes); // 读取二进制
(3) 第三方jar(Servlet3.0之前)
commons-fileupload.jar,commons-io.jar
java
// 用于解析上传文件
ServletFileUpload sf = new ServletFileUpload(new DisFileItemFactory());
// 判断是否文件上传
boolean isFileUpload = sf.isMultipartContent(req);
// 解析
List<FileItem> fileList = sf.paseRequest(req);
for(FileItem fi : fileList) {
boolean isFormItem = fi.isFormField(); // true表单项目,false文件项目
fi.getFieldName(); // 获取表单name属性
fi.getString(); // 获取表单项目值
fi.getName(); // 获取上传文件的文件名
fi.write(file); // fi.write("d:\\"+fi.getName()) 将上传文件写到file
}
5.3 文件下载
5.3.1 共享文件下载
使用a超链接,下载公开文件
java
<a href="xx.zip" > // 浏览器不识别的文件,会直接下载
<a href="xx.txt" download > // 浏览器识别的文件会默认打开,指定download将其下载
<a href="xx.txt" download="xx.png" > // 可以指定下载后的文件名
5.3.2 私有文件下载
使用文件输出流
java
FileInputStream fis = new FileInputStream(file); // 服务器获取文件
res.setContentType("application/octet-stream") // 设置响应为浏览器无法处理的类型
// 或者 res.setContentType("application/x-msdownload")
// 设置响应头
res.setHeader("Content-Disposition", "attachment;filename=" + file.getName())
// Content-Disposition 标识收到的数据处理方式
// attachment表示是附件,可以下载
// 新建输出流
BufferedOutputStream bos = new BufferedOutputStream(res.getOutputStream());
// 输出数据
int len;while((len=fi.read(byte[]))!=-1) { bos.write(b, 0, len); }
bos.close();
fi.close();
注释:文件名转码(idea默认utf-8,http传送默认使用iso-8859-1)
java
byte[] b = file.getName().getBytes(utf-8); // 获取utf8字节
String name = new String(b, "ISO-8859-1"); // 将字节转为sio-8859-1
5.4 特殊文件
5.4.1 properties
java
properties
#注释内容
key=value // 只能是键值对,键不能重复
java
// 读取文件
Properties p = new Properties();
// 读取项目下文件
Reader r = new FileReader(new File("src/xx.properties"));
InputStream is = new FileInputStream(new File("src/xx.properties")
p.load(Reader | InputStream)
// 获取值
String val = p.getProperty("key");
// 获取键
Set<String> keys = p.stringPropertyNames();
// 循环
p.forEach((k,v) -> ... )
// 改内存值,文件实际内容不变
p.setProperty(key, value);
// 保存文件,修改的内存值保存到文件
p.store(Writer| OutputStream, 注释)
6 XML
可扩展标记语言(可存储数据结构和数据,作为系统配置文件,数据传输)
注释:<!-- 注释内容 -->
声明:<?xml version="1.0" encoding="UTF-8" />
内容:<标签 属性="值">...</标签> 注释:xml必须且只能有一个根标签,一般成对出现,必须正确嵌套。标签必须自定义,区分大小写,必须正确嵌套。属性必须字母数字下划线,用引号括起来
小于号(<):<
大于号(>):>
&:&
单引号('): '
双引号("): "
包含特殊符号内容:<!CDATA\[内容]>
写数据:字符串拼接xml格式数据,io流输出
约束文档:新建.dtd文件(dtd不能约束数据类型),新建.xsd文件(可以约束数据类型)
java
<!ELEMENT 书架(书+)> 加号(+)表示至少一个子
<!ELEMENT 书(书名, 作者)>
<!ELEMENT 书名(#PCDATA)> #PCDATA可存放内容
引入约束:<!DOCTYPE xml根标签名 system "xx.dtd"> //引入xml同级dtd文件