Java学习笔记十二(异常与IO)

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必须且只能有一个根标签,一般成对出现,必须正确嵌套。标签必须自定义,区分大小写,必须正确嵌套。属性必须字母数字下划线,用引号括起来

小于号(<):&lt;

大于号(>):&gt;

&:&amp;

单引号('): '

双引号("): &quot;

包含特殊符号内容:<!CDATA\[内容]>

写数据:字符串拼接xml格式数据,io流输出

约束文档:新建.dtd文件(dtd不能约束数据类型),新建.xsd文件(可以约束数据类型)

java 复制代码
<!ELEMENT 书架(书+)>			加号(+)表示至少一个子
<!ELEMENT 书(书名, 作者)>			
<!ELEMENT 书名(#PCDATA)>			#PCDATA可存放内容

引入约束:<!DOCTYPE xml根标签名 system "xx.dtd"> //引入xml同级dtd文件

相关推荐
一只旭宝17 分钟前
五种线程池设计
c++·笔记
冬夜戏雪1 小时前
学习日记-LRU缓存成员变量,入参day1
学习
深念Y1 小时前
Windows 11 工具链部署与 SSH 踩坑笔记
windows·笔记·ssh
Sunshing151 小时前
非自治连续系统稳定性定义与定理判据
笔记·学习
苏灵凯1 小时前
Codex 官网前端可以抄吗?从设计到实现的技术拆解
笔记·ai·agent·codex·deepseek
andrsted2 小时前
老师可以用小程序在线整理题库、课堂检测和错题集
学习·微信小程序·小程序·学习方法
zhangrelay3 小时前
手机-笔电-等数码产品-电池健康的一些数据-2026
笔记·学习·锂电池
苏子寒4 小时前
Nano-VLLM全代码解析笔记(10)-GemmaRMSNorm和MRoPE
笔记·机器学习·ai·nlp·vllm
y = xⁿ1 天前
DeepSeek Harness 学习日记:关于Agent接口,工具调用的底层实现
android·java·学习