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数据。
public void fn() { try { 处理… // throw new Exception(); } catch (Exception e) { 异常处理代码… // 注释:异常时,catch中的return覆盖try中的return值返回。 } finally { 终止时运行代码… } }1.2.2 抛出异常
public void fn() throws Exception{ 处理… // throw new Exception(); }1.2.3 RuntimeException
注释:throw RuntimeException 外层不try catch 也可不做任何处理
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
注释:只适合做文件复制,不适合处理字符串数据,读取中文会截断文字导致乱码(可通过一次读取全部数据解决)byte[f.length] 或 byte[] b = f.readAllBytes(); 但是文件太大会内存溢出。
// 一个字节一个字节读取 FileInputStream fis = new FileInputStream(File | fileName); // 创建流 int b; while( (b=fis.read()) != -1) { // 读取一个字节,读到-1结束 // 可以用(char)b;强转 输出字节 } fis.close();// 读取字节数组 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
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) 关闭流
// 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) { } } }// JDK7 try (FileInputStream fis = new FileInputStram(file); FileOutputStream fos = new FileOutputStream(file);) { // 括号中只能写实现了AutoCloseable接口的对象 } catch (Exception e) { } // 不用写finally关闭流,自动关闭// 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个字节到缓冲区内存,有内存读内存数据,没有内存读文件到缓冲区。
// 一个字符一个字符读取 FileReader fr = new FileReader(File | fileName); // 文件不存在会报错 int ch; while (( ch = fr.read() ) != -1) { // 读取一个英文或一个中文,返回中文或英文十进制数值,-1结束 (char)ch; }// 读取字符数组 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
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
BufferedInputStream bis = new BufferedInputStream(InputStream); int b; while( (b=bis.read()) != -1) { // 读一个字节 }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
BufferedOutputStream bos = new BufferedOutputStream(InputStream); bos.write(int); // 写出1个字节 bos.write(byte[]);// 写出一个数组 bos.write(byte[], 开始下标, 长度); // 按下标长度写出数组(3) 字符输入缓冲流:BufferedReader
// 基本字符流自带缓冲区,缓冲存流提升不明显。文件编码与程序编码一致,br读文件才不会乱码
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); }BufferedReader br = new BufferedReader(Reader [, int]); String line; while((line = br.readLine()) != null) { // 没有数据返回null,不会读取到回车换行符 String str = line; }(4) 字符输出缓冲流:BufferedWriter
BufferedWriter bw = new BufferedWriter(Writer); // 开启追加文本模式在Writer构造器指定 bw.write(97 | char | String); // 写int输出char bw.newLine(); // 换行输出(跨平台换行)3.4 转换流
注释:JDK11将其淘汰了,当字节流需要使用字符流方法时使用。
(1) 字符输入转换流:InputStreamReader
解决BuifferedReader文件与程序编码不一致的乱码问题
InputStreamReader isr = new InputStreamReader(InputStream, ["字符集"]) // 字节流转成字符流读取 BufferedReader br = new BufferedReader(isr);(2) 字符输出转换流:OutputStreamWriter
注释:也可使用 byte[] bytes = str.getBytes(字符集)方法获取指定字符集的字符串二进制数据
OutputStreamWriter osw = new OutputStreamWriter(OutputStream, ["字符集"]) // 字符流转成字节流输出 BufferedWriter bw = new BufferedWriter(osw);(3) JDK11替代方案:FileReader,FileWriter
FileReader fr = new FileReader(File, Charset.forName("GBK")) FileWriter fw = new FileWriter(File, Charset.forName("GBK"))3.5 打印流
注释:以字节或字符形式输出文本
(1) 字节输出打印流:PrintStream
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
PrintWriter pw = new PrintWriter(Writer) pw.write(97); // 输出a pw.print(97); // 输出97 pw.println(97); // 换行输出,自动刷新3.6 数据流
注释:目的是存储数据,不是人为观看用的
(1) 数据输入流:DataInputStream
DataInputStream dis = new DataInputStream(InputStream) dis.write基本类型(数据); // 可输出多次相同类型 dis.writeUTF(str);(2) 数据输出流:DataOutputStream
DataOutputStream dos = new DataOutputStream(OutputStream) dos.read基本类型(); // 可读取多次相同类型 dos.readUTF();3.7 序列化流
注释:写入写出对象数据
(1) 序列化流:ObjectOutputStream
ObjectOutputStream oos = new ObjectOutputStream(OutputStream) oos.write基本类型(数据); oos.writeObject(对象); // 写出的文件看不懂,类似于加密(2) 反序列化流:ObjectInputStream
ObjectInputStream dis = new ObjectInputStream(InputStream) 类 对象 = (类) dis.readObject();注释:序列化对象类需要实现Serizlizable接口,对象中不定义版本号(默认版本号)每次修改文件会发生改变,导致返序列号失败,可手动追加版本号(private static final longserialversionuid= 1l;),序列化多个对象用 ArrayList,不序列化某个属性(privatetransientString 属性;)
3.8 压缩流
(java.util.zip)
(1) 压缩流:
// 单文件压缩 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();// 多文件压缩 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()读到的字节不一样
String str1 = new String(bytes[], [charsetName]); // 指定字符集获取文本 str2.getBytes(charsetName); // 指定字符集或取字节(gbk, iso8859-1,…)5 实用案例
5.1 文件复制
5.1.1 基本流
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提供
FileUtils.copyFile(f1, f2); // 复制文件 FileUtils.copyDirectory(dir1, dir2); // 复制文件夹 FileUtils.readFileToString(); // 读数据 FileUtils.writeStringToFile(str); // 写数据5.2 文件上传
5.2.1 前端上传文件
<form method="post" encType="multipart/form-data"> 以多段拼接二进制发送服务器 <input type="file" /> </form>5.2.2 后端获取上传的文件
(1) Servlet3.0注解
@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读取
ServletInputStream si = req.getInputStream();// 获取文件流 byte [] bytes = new bytes[1024]; si.read(bytes); // 读取二进制(3) 第三方jar(Servlet3.0之前)
commons-fileupload.jar,commons-io.jar
// 用于解析上传文件 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超链接,下载公开文件
<a href="xx.zip" > // 浏览器不识别的文件,会直接下载 <a href="xx.txt" download > // 浏览器识别的文件会默认打开,指定download将其下载 <a href="xx.txt" download="xx.png" > // 可以指定下载后的文件名5.3.2 私有文件下载
使用文件输出流
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)
byte[] b = file.getName().getBytes(utf-8); // 获取utf8字节 String name = new String(b, "ISO-8859-1"); // 将字节转为sio-8859-15.4 特殊文件
5.4.1 properties
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文件(可以约束数据类型)
<!ELEMENT 书架(书+)> 加号(+)表示至少一个子 <!ELEMENT 书(书名, 作者)> <!ELEMENT 书名(#PCDATA)> #PCDATA可存放内容引入约束:<!DOCTYPE xml根标签名 system "xx.dtd"> //引入xml同级dtd文件