Java学习-07 IO学习
I : 即input,代表读取。O:即output,代表输出。
1、File
主要字段:
示例:
System.out.println(File.pathSeparator);
System.out.println(File.pathSeparatorChar);
System.out.println(File.separator);
System.out.println(File.separatorChar);;
输出:
;
;
\
\
构造方法:
常用方法:
createNewFile, delete
, exists(),getAbsolutePath(),getName(),getParent(),getPath(),isAbsolute(),isDirectory(),isFile(),length(),listFiles(),listFiles(FileFilter filter),listFiles(FilenameFilter filter),mkdir(),renameTo(File dest)
使用FileFilter 和匿名内部类案例:
File[] files2 = f.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".jpg");
}
});
if (files2 != null && files2.length > 0){
for (File file :
files2) {
System.out.println("找到了一个jpg文件:" + file.getAbsolutePath());
}
}
2、IO流
IO流概述:
可以将这种数据传输操作,看做一种数据的流动 , 按照流动的方向分为输入Input和输出Output
Java中的IO操作主要指的是 java.io包下的一些常用类的使用. 通过这些常用类对数据进行读取(输入Input) 和 写出(输出Output)
IO流的分类:
- 按照流的方向来分,可以分为:输入流和输出流.
- 按照流动的数据类型来分,可以分为:字节流和字符流
字节流:
- 输入流 : InputStrea
- 输出流 : OutputStream
字符流:
- 输入流 : Reader
- 输出流 : Writer
一切皆字节:
计算机中的任何数据(文本,图片,视频,音乐等等)都是以二进制的形式存储的.
在数据传输时 也都是以二进制的形式存储的.
后续学习的任何流 , 在传输时底层都是二进制.
2.1、FileOutputStream
OutputStream本身是输出流的抽象基类,所以使用它的实现类。
FileOutputStream的三种write方法:
一定要注意使用close方法释放资源。
案例练习:
package java03.com.app.core.section4;
import java.io.FileOutputStream;
import java.io.IOException;
public class OutputStreamDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream(".\\a.txt");
fos.write(65);
fos.write(66);
fos.write(67);
byte[] bytes = {65,66,67};
fos.write(bytes);
byte[] bytes1 = "abc".getBytes();
fos.write(bytes1);
fos.write(bytes1, 1, 2);
System.out.println("end");
fos.close();
}
}
/*
输出结果:
ABCABCabcbc
*/
需要注意的是,第二次打开这个文档的时候,如果还是同样的命令,那么会先清空文档中的内容,再写入,如果不想清空,想在原来的内容后边追加,可以:
把new FileOutputStream(".\a.txt")写为:new FileOutputStream(".\a.txt",true);第二个参数就是表示是否追加。
注意,不能读取字符串,会导致乱码,因为对于UTF-8编码集,字符有的占两个字节,有的占三个字节。
2.2、FileInputStream
InputStream本身是输出流的抽象基类,所以使用它的实现类。
FileInputStream的三种read方法:
机翻存在一定问题,这里解释一下:
- 第一种不传参数的是读取单个字节数据,然后返回读取的字节数据。
- 第二种会读取最多b.length个字节,返回实际读取的字节数,注意是实际,比如你的b数组的长度为10,但是最后读取的字节不够10个,比如-还剩5个,那么会返回5,而不是10!
- 第三种从输入流最多读取len个字节的数据,并放入字节数组b中,是从第二个参数off的位置开始读取, 同样返回的是实际读取的长度。
案例演示:
第一种读取方式:
package java03.com.app.core.section4;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 10:37
* @Modified By:
*/
public class InputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream(".\\a.txt");
// a.txt : ABCABCabcbc
char r1 = (char) fis.read();
int r2 = fis.read();
byte r3 = (byte) fis.read();
System.out.println(r1);
System.out.println(r2);
System.out.println(r3);
}
}
/*
输出:
A
66
67
*/
第二种读取方式:
package java03.com.app.core.section4;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 10:37
* @Modified By:
*/
public class InputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream(".\\a.txt");
// a.txt : ABCABCabcbc
byte[] bytes = new byte[5];
int len = fis.read(bytes);
System.out.println("读取到的长度为:" + len + ", 字符为:" + new String(bytes,0,len));
len = fis.read(bytes);
System.out.println("读取到的长度为:" + len + ", 字符为:" + new String(bytes,0,len));
len = fis.read(bytes);
System.out.println("读取到的长度为:" + len + ", 字符为:" + new String(bytes,0,len));
fis.close();
}
}
/*
读取到的长度为:5, 字符为:ABCAB
读取到的长度为:5, 字符为:Cabcb
读取到的长度为:1, 字符为:c
*/
第三种读取方式:
package java03.com.app.core.section4;
import java.io.FileInputStream;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 10:37
* @Modified By:
*/
public class InputStreamDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream(".\\a.txt");
// a.txt : ABCABCabcbc
byte[] bytes = new byte[5];
int length = bytes.length;
// 为了便于观察,把这里的bytes数组元素全部变为 *
for (int i = 0; i < length; i++) {
bytes[i] = '*';
}
System.out.println("读取前bytes中字符为:" + new String(bytes,0,length));
int len = fis.read(bytes, 1, 3);
System.out.println("读取到的长度为:" + len + ", bytes中字符为:" + new String(bytes,0,length));
len = fis.read(bytes, 1, 3);
System.out.println("读取到的长度为:" + len + ", bytes中字符为:" + new String(bytes,0,length));
len = fis.read(bytes, 1, 3);
System.out.println("读取到的长度为:" + len + ", bytes中字符为:" + new String(bytes,0,length));
fis.close();
}
}
/*
读取前bytes中字符为:*****
读取到的长度为:3, bytes中字符为:*ABC*
读取到的长度为:3, bytes中字符为:*ABC*
读取到的长度为:3, bytes中字符为:*abc*
*/
可以看到,第三种方式读取的时候,读取的长度不再是bytes.length,而是第三个参数len,并且在存放的时候,会从第二个参数 off的位置开始往bytes数组中存放。
注意不能写字符串。
2.3、Writer
以下为它提供的write方法,可以看到,除了可以写字节,还可以直接写字符串。
用法和前面的字节流用法一样,所以就简单的举个栗子,然后主要说一说其他的方法。
abstract void | flush() | 刷新流。 |
---|
先说说这个flush,这对应一个缓冲区,为什么要缓冲呢?因为计算机底层是二进制,传递的时候是一个字节一个字节的,但是对于UTF-8中的很多字符,它们都是占好几个字节,所以需要缓冲区先把它们拼起来,然后再放进去,这样就能避免乱码问题,所以你写入的东西,都是先保存在缓冲区的,直到调用flush方法,强制刷新缓冲区,才能把东西放进文档,close会自动调用。
比如如下代码:
package java03.com.app.core.section4;
import java.io.FileWriter;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 11:21
* @Modified By:
*/
public class WriterDemo {
public static void main(String[] args) throws IOException {
FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
writer.write("艳阳天那个风光好,");
writer.write("红的花是绿的草,");
writer.write("我乐乐呵呵向前跑,");
writer.write("踏遍青山人未老。");
// writer.close();
}
}
/*
会发现test.txt中什么也没有
*/
如果调用flush方法:
package java03.com.app.core.section4;
import java.io.FileWriter;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 11:21
* @Modified By:
*/
public class WriterDemo {
public static void main(String[] args) throws IOException {
FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
writer.write("艳阳天那个风光好,");
writer.write("红的花是绿的草,");
writer.write("我乐乐呵呵向前跑,");
writer.write("踏遍青山人未老。");
writer.flush();
// writer.close();
}
}
/*
会看到test.txt中:
艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
*/
然后需要说说这个append方法,很有意思。
先上代码:
package java03.com.app.core.section4;
import java.io.FileWriter;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 11:21
* @Modified By:
*/
public class WriterDemo {
public static void main(String[] args) throws IOException {
FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
writer.append("艳阳天那个风光好,").append("红的花是绿的草.");
writer.close();
}
}
/*
test.txt中:
艳阳天那个风光好,红的花是绿的草.
*/
可以看到,这次不用每次writer了,直接在后边.append就可以放入大量文字,因为它返回的是writer对象。
需要注意的是,这个append也只是在本次打开有效,下次再打开这个文件,用append写入的时候,可不是在原文件内容后边追加,是先清空源文件内容,再写入,控制在原内容后边追加的还是创建Writer时的第二个参数true,同上边的字节流。
那么append的第三种是什么意思呢?
package java03.com.app.core.section4;
import java.io.FileWriter;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 11:21
* @Modified By:
*/
public class WriterDemo {
public static void main(String[] args) throws IOException {
FileWriter writer = new FileWriter("src/java03/com/app/core/section4/test.txt");
writer.append("艳阳天那个风光好,").append("红的花是绿的草.").append("踏遍青山人未老。", 2,4);
writer.close();
}
}
/*
test.txt中:
艳阳天那个风光好,红的花是绿的草.青山
*/
原来是把字符串按照start和end进行切片后,把切片得到的子字符串追加,注意是左闭右开的,即不包含右边索引对应的字符。
2.4 Reader
先说基本的Reader方法:三种read
可以看到,这三种和字节流的基本一样,只是把byte[] 换成了char[] ,所以用法都是一样的。
演示代码:
package java03.com.app.core.section4;
import java.io.FileReader;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 12:05
* @Modified By:
*/
public class ReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("src/java03/com/app/core/section4/test.txt");
// test.txt 内容:艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
char[] chars = new char[9];
int read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
fr.close();
}
}
/*
读取到9个字符,分别是:艳阳天那个风光好,
读取到9个字符,分别是:红的花是绿的草,我
读取到9个字符,分别是:乐乐呵呵向前跑,踏
读取到7个字符,分别是:遍青山人未老。,踏
*/
可以看到最后的输出怎么多了个,踏
,这是啥?还记得缓冲区吗?这就是因为读取到的字符,是先保存在缓冲区的,而最后一次读取,要读取9个字符,但是只剩下7个字符了,那怎么办?从缓冲区哪里拿两个过来补上。见图:
第四次取的时候,只取到了7个字符,所以去上一行读取的拿了两个过来补上,对应黄色框框。
2.5、关于读入时的结束判断
不论是字节读取还是字符读取,读取到最后都会会返回-1, 所以可以根据这个判断是否读取到了最后。
还是拿上一节的代码,再读取一次,会看到最后输出变成了“读取到-1个字符,分别是:遍青山人未老。,踏”,返回了-1,表明没有读取到新的字符,所以没有修改chars数组,因此最后的输出文字和上一行的一样。
package java03.com.app.core.section4;
import java.io.FileReader;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 12:05
* @Modified By:
*/
public class ReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("src/java03/com/app/core/section4/test.txt");
// test.txt 内容:艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
char[] chars = new char[9];
int read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
read = fr.read(chars);
System.out.println("读取到" + read + "个字符," + "分别是:" + new String(chars, 0, chars.length));
fr.close();
}
}
/*
读取到9个字符,分别是:艳阳天那个风光好,
读取到9个字符,分别是:红的花是绿的草,我
读取到9个字符,分别是:乐乐呵呵向前跑,踏
读取到7个字符,分别是:遍青山人未老。,踏
读取到-1个字符,分别是:遍青山人未老。,踏
*/
2.6、转换流
转换流 将字节流转换成字符流,使用了装饰者模式,也可以成为装饰器设计模式。
包括两个:InputStreamReader 和OutputStreamWriter,见名知意,就是把字节流变成字符流。
可以传递输入流和字符集。
练习代码:
package java03.com.app.core.section4;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 13:30
* @Modified By:
*/
public class InputStreamReaderDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
// test.txt 内容:艳阳天那个风光好,红的花是绿的草,我乐乐呵呵向前跑,踏遍青山人未老。
// 将字节输入流转换为字符输入流 参数为要转换的字节流和编码集
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
// 查看一下所使用的编码
System.out.println(isr.getEncoding());
while (true){
int read = fis.read();
int c = isr.read();
if(c==-1){
break;
}
System.out.println("转换之前返回的字节数据是:" + read + ",转换为字符是:" + (char) read);
System.out.println("转换之后返回的字节数据是:" + c + ",转换为字符是:" + (char)c);
System.out.println("------------------------------------------------------------------");
}
fis.close();
}
}
/*
UTF8
转换之前返回的字节数据是:232,转换为字符是:è
转换之后返回的字节数据是:65533,转换为字符是:�
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:65533,转换为字符是:�
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:38451,转换为字符是:阳
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:22825,转换为字符是:天
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:37027,转换为字符是:那
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:20010,转换为字符是:个
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:39118,转换为字符是:风
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:20809,转换为字符是:光
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:22909,转换为字符是:好
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:65292,转换为字符是:,
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:32418,转换为字符是:红
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:30340,转换为字符是:的
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:33457,转换为字符是:花
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:26159,转换为字符是:是
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:32511,转换为字符是:绿
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:30340,转换为字符是:的
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:33609,转换为字符是:草
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:65292,转换为字符是:,
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:25105,转换为字符是:我
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:20048,转换为字符是:乐
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:20048,转换为字符是:乐
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:21621,转换为字符是:呵
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:21621,转换为字符是:呵
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:21521,转换为字符是:向
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:21069,转换为字符是:前
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:36305,转换为字符是:跑
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:65292,转换为字符是:,
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:36367,转换为字符是:踏
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:36941,转换为字符是:遍
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:38738,转换为字符是:青
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:23665,转换为字符是:山
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:20154,转换为字符是:人
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:26410,转换为字符是:未
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:32769,转换为字符是:老
------------------------------------------------------------------
转换之前返回的字节数据是:-1,转换为字符是:
转换之后返回的字节数据是:12290,转换为字符是:。
------------------------------------------------------------------
*/
这个输出这里,有一点问题,前边两个不知道为什么显示错误,但是能看到这个转换前和转换后的对比,后边能正确输出,可能是IDEA的问题。
OutputStreamWriter:
package java03.com.app.core.section4;
import java.io.*;
import java.nio.charset.StandardCharsets;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 14:01
* @Modified By:
*/
public class OutputStreamWriterDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
fos.write('帅');
// 将字节输入流转换为字符输入流 参数为要转换的字节流和编码集
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);
// 查看所使用的编码集
System.out.println(osw.getEncoding());
osw.write("帅");
osw.close();
}
}
输出:
2.7、PrintStream和PrintWriter
它们都属于打印流,顾名思义,就是为了输出文本的。它属于处理流,使用处理流的方法:用处理流来包装节点流,程序通过处理流来执行输入输出功能,而节点流与底层的I/O设备、文件交互。
简单代码演示:
package java03.com.app.core.section4;
import java.io.FileNotFoundException;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 14:00
* @Modified By:
*/
public class PrintStreamDemo {
public static void main(String[] args) throws FileNotFoundException {
PrintStream ps = new PrintStream("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
ps.println("面朝大海");
ps.println("春暖花开");
/*test.txt:
面朝大海
春暖花开
*/
PrintWriter pw = new PrintWriter("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
pw.println("王大卖瓜");
pw.println("老鼠的儿子会打洞");
ps.flush();
ps.close();
pw.flush();
pw.close();
/*test.txt:
王大卖瓜
老鼠的儿子会打洞
*/
}
}
/*
最终test.txt:
王大卖瓜
老鼠的儿子会打洞
*/
我们一直使用的System.out就是PrintStream类
2.8、BufferedReader
缓冲流,BufferedReader流具有缓冲功能,他可以一次读取一行文本,以换行符为标志,如果没有读到换行符,那么程序会堵塞,等到读到换行符为止。
因为它具有一个readLine方法,可以方便的一次读取一行内容,所以经常把读取文本内容的输入流包装为BufferedReader,用来方便的读取输入流的文本内容。
案例演示:
package java03.com.app.core.section4;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 17:07
* @Modified By:
*/
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("F:\\IdeaProjects\\JavaEE_Learning\\src\\java03\\com\\app\\core\\section4\\test.txt");
/*
test.txt内容:
王大卖瓜
老鼠的儿子会打洞*/
BufferedReader br = new BufferedReader(fr);
String s = br.readLine();
System.out.println(s);
}
}
/*
王大卖瓜
*/
2.9、利用IO流进行异常日志收集
程序在运行时总会出现异常,我们不可能一直盯着控制台去看,那么就需要收集这些异常信息。简单练习如下:
package java03.com.app.core.section4;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 17:14
* @Modified By:
*/
public class ExceptionDemo {
public static void main(String[] args) throws FileNotFoundException {
//收集异常信息
try {
String s = null;
s.toString();
}catch (Exception e){
PrintWriter pw = new PrintWriter(".\\bug.txt");
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
pw.println(format.format(new Date()));
e.printStackTrace(pw);
pw.close();
}
}
}
/*
可以看到bug.txt中多了几行文字:
2020-08-07 17:19
java.lang.NullPointerException
at java03.com.app.core.section4.ExceptionDemo.main(ExceptionDemo.java:19)
*/
这个就是简单的演示一下,了解就行,因为有好多封装很好地异常日志类可以使用。
3、简单的加密解密
因为计算机底层保存的都是二进制,所以可以简单地进行加密解密操作,即通过异或,异或的规则为:pqq = p
那么,第一次异或即为加密,第二次即为解密。
package java03.com.app.core.section4;
import java.io.*;
import java.util.Scanner;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 18:40
* @Modified By:
*/
public class EncryptionDemo {
public static void main(String[] args) throws IOException {
Scanner input = new Scanner(System.in);
System.out.println("请输入文件的绝对路径:");
String fileName = input.nextLine();
// 为了得到上一级路径,需要用File读入
File oldFile = new File(fileName);
// 对于加密的文件,加上前缀mi-,区分
File newFile = new File(oldFile.getParent(), "mi-" + oldFile.getName());
// 为了进行读取写出,需要流
FileInputStream fis = new FileInputStream(oldFile);
FileOutputStream fos = new FileOutputStream(newFile);
// 循环读入进行加密,加密解密原理为 进行^操作。p^4^4 = p, 任何一个数连续异或同一个数两次得到的结果还是它
System.out.println("正在进行操作,这可能需要一段时间");
while (true){
// 每次读取一个字节
int b = fis.read();
// 如果返回 -1 表明读取完毕
if (b == -1) break;
fos.write(b^4);
}
System.out.println("加密/解密完成");
}
}
/* 第一次我们输入要加密的文件路径
请输入文件的绝对路径:
C:\Users\zlz1314\Desktop\close.png
正在进行操作,这可能需要一段时间
加密/解密完成
*/
/*第二次我们输入加密了的文件的路径进行解密
请输入文件的绝对路径:
C:\Users\zlz1314\Desktop\mi-close.png
正在进行操作,这可能需要一段时间
加密/解密完成
*/
4、Properties
properties文件与properties类,配置文件格式,它是Map类,所以存的是键值对。
put放入键值对,store保存到本地文件,因为需要I/O操作,所以需要创建I/O流。
简单实例:
package java03.com.app.core.section4;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 17:26
* @Modified By:
*/
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
// 存放键值对
properties.put("1", "雕虫小技");
properties.put("2", "竟敢班门弄斧!");
// 保存为文件, 需要输出流
FileWriter fw = new FileWriter(".\\a.txt");
properties.store(fw, "最强法海");
// 不要忘记关闭流
fw.close();
}
}
/* 第一行乱码,使用Unicode解析可以看到就是最强法海四个字
#\u6700\u5F3A\u6CD5\u6D77
#Fri Aug 07 17:32:12 CST 2020
1=雕虫小技
2=竟敢班门弄斧\!
*/
保存完了,怎么读取呢?load方法。
package java03.com.app.core.section4;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 17:26
* @Modified By:
*/
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
Properties properties = new Properties();
FileReader fr = new FileReader(".\\a.txt");
properties.load(fr);
System.out.println(properties.getProperty("1"));
System.out.println(properties.get("2"));
}
}
/*
雕虫小技
竟敢班门弄斧!
*/
可以看到,这个get和getProperty都是可以的。
5、序列化和反序列化
目前我们能在文件中存取文本了,那能不能存取类呢?所以出现了序列化与反序列化技术,可以把类放进去!这个简直太牛了,所以一经提出,就被广泛使用,但是听老师说,近两年java官方给出的一份报告显示这个技术会引起大量的bug,java官方将推出新技术取代这个技术,所以能不用就不用,万一过两年没了呢。
要实现序列化,必须实现Serializable接口。然后使用的是ObjectInputStream和ObjectOutputStream,通过readObject和writeObject进行读写。
练习代码:
package java03.com.app.core.section4;
import java.io.*;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 17:40
* @Modified By:
*/
public class SerializableDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//序列化与反序列化
/*Book b = new Book("金苹果","讲述了种植过程");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(".//b.txtx"));
oos.writeObject(b);
oos.close();*/
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(".//b.txtx"));
Object o = ois.readObject();
System.out.println(o);
Book b = (Book)o;
System.out.println(b.getName());
System.out.println(b.getInfo());
ois.close();
}
static class Book implements Serializable {
private String name;
private String info;
public Book(String name, String info) {
this.name = name;
this.info = info;
}
public Book() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
}
}
/*
Book{name='金苹果', info='讲述了种植过程'}
金苹果
讲述了种植过程
*/
序列化与反序列化下面被注释的是序列化的代码,因为没有什么输出,文档也是打不开的,所以就不做演示了,可以看到反序列化之后可以正确的输入这个类,而且可以进行类型强转,从而可以访问类的方法。
需要注意的是,如果,这个类的属性中还有其他的类,那么这个类也必须实现Serializable接口。
6、try-catch对于I/O流的支持
try-catch现在支持自动关闭I/O流,在之前的老版本还需要写在finall中,但是有很多不方便,比如,I/O流需要写在try里面才能捕捉,那我之后的代码还要用,怎么办,我有多个流怎么办,等等问题,所以后来推出了1.9版本中的写法,可以写在try外面,然后把引用给try的(),有多个可以用;分开。
注意的是,所有可以被try-catch自动关闭的,必须实现Closeable接口。
案例演示:
package java03.com.app.core.section4;
import java.io.*;
/**
* @Author: deemoHui
* @Description:
* @Date Created in 2020-08-07 18:00
* @Modified By:
*/
public class TryCatchIODemo {
public static void main(String[] args) throws IOException {
//try-with-resources
/*try {
FileReader fr = new FileReader(".//a.txt");
int c = fr.read();
System.out.println((char)c);
fr.close();
} catch (IOException e) {
e.printStackTrace();
}*/
//jdk9
FileReader fr = new FileReader(".//a.txt");
// a.txt : 哈哈啊哈
PrintWriter pw = new PrintWriter(".//bug.txt");
try(fr;pw){
int c = fr.read();
System.out.println((char)c);
pw.println((char)c);
}catch (IOException e) {
e.printStackTrace();
}
CloseDemo c = new CloseDemo();
try(c){
}catch (Exception e){
}
}
static class CloseDemo implements Closeable{
@Override
public void close() throws IOException {
System.out.println("close方法执行。");
}
}
}
/*
可以看到bug.txt中多了哈哈啊哈
close方法执行。
*/