Java-IO流
Java-IO流
学习视频-奇酷教育Java-IO流:视频链接
Java-IO流
java.io
File文件操作
-
创建文件对象
-
常见API
-
目录操作
-
package com.tang.file; import org.junit.Assert; import org.junit.Test; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; public class FileTest { @Test public void createFileObj() throws URISyntaxException { /** * File 代表磁盘中的文件、目录 * * java.io 包下 * * 字符串路径表示形式: * 在 window 操作系统中, 路径用'\'进行分隔, 在编写路径的时候, 需要对 \ 进行转义 * 在 linux 操作系统中, 路径用'/'进行分隔, 在使用的时候不需要进行转义 * * 运行时错误: java.lang.NoClassDefFoundError: org/hamcrest/SelfDescribing * 原因: junit4.11 及以上版本, 无 hamcrest类 * 解决方案一: 降低 junit 到 4.10及以下版本 * 解决方案二: 导入 hamcrest-core-1.3.jar */ //构建了一个File对象, 指向磁盘中某一个目录 File file1 = new File("D:\\BianCheng\\ideaDown"); //基于 window 路径风格 File file2 = new File("D:/BianCheng/ideaDown"); //基于 linux 路径风格 //构建了一个File对象, 指向磁盘中某一个文件 File file3 = new File("D:/BianCheng/ideaDown/赤伶.m4a"); //基于 linux 路径风格 //构建了一个File对象, 指向磁盘中不存在的 文件/目录 File file4 = new File("D:\\BianCheng\\xxx.jpg"); //构建File对象的第二种方式, 和file1对象等价 File file5 = new File("D:\\BianCheng", "ideaDown"); //和 构建的 file3 对象等价, 更适合处理文件 File file6 = new File("D:/BianCheng/ideaDown", "赤伶.m4a"); // File 对象的 第三种构建方式 File parent = new File("D:/BianCheng/ideaDown"); File file7 = new File(parent, "赤伶.m4a"); // File 对象的 第四种构建方式, 基于文件协议 File file8 = new File(new URI("file:///D:/IT/1_lib架包/hamcrest-core-1.3.jar")); System.out.println(file1); System.out.println(file2); System.out.println(file3); System.out.println(file4); System.out.println(file5); System.out.println(file6); System.out.println(file7); System.out.println(file8); } @Test public void fileApi() throws IOException { //创建目录 //使用相对路径, 创建一个File对象 //File file = new File("/abc/test"); /* 如果地址以 / 开头, 代表使用的是绝对路径 绝对路径, 从当前项目所在的盘符开始 */ //相对路径 //File file = new File("abc/123.jpg"); //File file = new File("./abc/123.jpg"); File file = new File("../abc/123.jpg"); /* 相对路径的表示方式有三种 abc/123.jpg ./abc/123.jpg ( 如果路径以 . 开头, 代表 当前路径 ) ../abc/123.jpg ( 如果路径以 .. 开头, 代表 当前路径的 上级路径 ) */ //获取目录名称 System.out.println(file.getName()); //获取 file 的父级路径 System.out.println(file.getParent()); //获取 file 的路径 System.out.println(file.getPath()); //获取 file 的绝对路径 (虚拟路径) System.out.println(file.getAbsolutePath()); //获取 file 的绝对路径 真实路径 System.out.println(file.getCanonicalPath()); /* 断言的内容为 true, 编译通过, 断言的内容为false, 编译失败 */ //断言 该目录 存在 //Assert.assertTrue(file.exists()); //断言可读 //Assert.assertTrue(file.canRead()); //断言可写 //Assert.assertTrue(file.canWrite()); //断言 file 是目录 //Assert.assertTrue(file.isDirectory()); //断言 file 是文件 //Assert.assertTrue(file.isFile()); //断言 file 隐藏 //Assert.assertTrue(file.isHidden()); } @Test public void fileDelete() { //创建 file 目录 File file = new File("D:\\IT\\JavaSE-狂神说\\abc\\123.jpg"); //断言 file 存在 Assert.assertTrue(file.exists()); //断言 file 是目录 Assert.assertTrue(file.isDirectory()); //删除 123.jpg 目录,断言删除失败 Assert.assertFalse(file.delete()); //创建 file2 文件 File file2 = new File(file, "a.txt"); //断言存在 Assert.assertTrue(file2.exists()); //断言 file2 是文件 Assert.assertTrue(file2.isFile()); //删除 a.txt,断言删除成功 Assert.assertTrue(file2.delete()); //删除目录,断言删除成功 Assert.assertTrue(file.delete()); } @Test public void fileOthers() { File file = new File("D:\\IT\\JavaSE-狂神说\\abc"); //获取 file 最后修改时间,返回一个时间戳 long l = file.lastModified(); //将其转成日期对象 Date date = new Date(l); //格式化 String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(date); System.out.println(format); //获取文件的大小, 无法直接获取目录的大小, 只能直接获取文件的大小 System.out.println(file.length());//0 File file2 = new File(file, "a.txt"); System.out.println(file2.length());//文件的大小 } @Test public void testCreateFile() throws IOException { //创建一个 File 文件对象 File file = new File("D:/abc/def", "123.txt"); //获取 file 的父级 文件对象 File parent = file.getParentFile(); //创建父级目录, // mkdir 只能创建 最后一层 目录 // mkdirs()可以创建多级目录, 如果要创建的目录已经存在,则忽略 parent.mkdirs(); //创建一个 文件, 不能创建 目录, 如果要创建的文件已经存在,则忽略 boolean newFile = file.createNewFile(); } @Test public void readDirectory() { //创建一个目录 对象 File directory = new File("D:/abc"); //读取目录下的所有 文件/目录 数据 String[] list = directory.list(); System.out.println(Arrays.toString(list)); // 比较常用的 获取 目录下所有的 资源 (包含文件 和 目录) File[] files1 = directory.listFiles(); System.out.println(Arrays.toString(files1)); //获取 目录下, 所有的文件 File[] files2 = directory.listFiles(File::isFile); System.out.println(Arrays.toString(files2)); //获取 目录下, 所有非空的 文件 File[] files3 = directory.listFiles(f -> f.isFile() && f.length() > 0); System.out.println(Arrays.toString(files3)); //过滤 文件名包含 File[] files = directory.listFiles((f, name) -> name.contains("a")); System.out.println(Arrays.toString(files)); } /** * 获取指定后缀的文件 */ public void searchFiles(File directory, String ext) { //获取当前目录下的 .java文件 和 子目录 File[] files = directory.listFiles(f -> f.isDirectory() || f.isFile() && f.getName().endsWith(ext)); //遍历 获取 ext 结尾的文件 for (File file : files) { if (file.isFile()) { //打印 .java文件 的路径 //System.out.println(file); //绝对路径 System.out.println(file.getAbsolutePath()); } else { //搜索 子目录下 的所有 .java文件 searchFiles(file, ext); } } } /** * 获取 指定目录下的 所有 .java文件 */ public void searchJavaFiles(File directory) { searchFiles(directory, ".java"); } public void searchJavaFiles(String path) { searchFiles(new File(path), ".java"); } @Test public void testSearchJava(){ searchJavaFiles("D:\\IT\\_JavaSE-狂神说"); } } -
删除指定的目录
-
搜索指定的文件
-
package com.tang.file; import org.junit.Test; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; public class FileRemoveTest { @Test public void TestRemove(){ /** * delete() 方法, 一旦删除, 不可恢复, 所以在删除数据的时候, 慎重一点 */ //removeFile(new File("D:\\abc")); List<File> files = searchFiles(new File("C:\\Users\\糖果\\Desktop\\Markdown学习\\web"), s -> s.getName().endsWith(".html")); for (File file : files) { System.out.println(file); } } /** * 删除指定的目录 * @param directory 要删除的目录 */ public void removeFile(File directory){ //delete() 可以直接删除文件, 或者 空的目录 if (directory.isFile()) directory.delete(); //获取 目录的: 子目录 子文件 File[] files = directory.listFiles(); for (File file : files) { if (file.isFile()){ //删除目录中的文件 file.delete(); }else { removeFile(file); } } //删除空目录 directory.delete(); } /** * 搜索指定的目录 * @param directory 要搜索的目录 * @param predicate 搜索条件 * @return */ public List<File> searchFiles(File directory, Predicate<File> predicate){ //返回存储文件的容器 List<File> files = new ArrayList<>(); //获取目录下的所有的文件 File[] list = directory.listFiles(f -> f.isDirectory() || predicate.test(f)); for (File file : list) { if (file.isFile()){ files.add(file); }else { files.addAll(searchFiles(file, predicate)); } } //返回目录中所有的文件 return files; } }
流的分类
-
方向
-
输入流
-
Reader(字符文件)
-
InputStreamReader
-
FileReader继承InputStreamReader
-
StringReader
-
BufferReader
-
-
InputStream(字节文件)
-
FileInputStream
-
BufferInputStream
-
ZipInputStream
-
-
ByteArrayInputStream
-
-
-
输出流
-
Writer(字符文件)
-
InputStreamWriter
-
FileWriter继承InputStreamWriter
-
StringWriter
-
BufferWriter
-
PrintWriter继承Writer
-
-
OutputStream(字节文件)
-
FileOutputStream
-
BufferOutputStream
-
ZipOutputStream
-
PrintStream
-
-
ByteArrayOutputStream
-
-
-
-
文件类型
-
字符流
-
Reader
-
Writer
-
package com.tang.io; import org.junit.Test; import java.io.*; import java.nio.charset.Charset; public class ReaderWriterTest { @Test public void testReader1(){ /** * Reader 代表从字符文件中读取数据 * 字符文件: 能用记事本打开的文件, 是字符文件 * * 常见的字符文件: * .txt , .java , .py , .php , .js , * .css , .html , .ini , conf ... * 字节文件: 存储的是流数据的文件, 不能用记事本打开 * .class , .doc , .xls , .ppt , .exe ... */ //创建一个File对象 File file = new File("D:\\abc\\m.ini"); // 创建一个Reader对象, 负责读取文件内容 // FileReader: 专门读取文件的字符流 // 每一个子类都有自己的特点, 所以, 在使用流的时候, 一般不推荐使用多态, 否则 会丢失 子类的特性 FileReader reader = null; try { reader = new FileReader(file); //读取文件, read() 每次读取一个字符, 返回该字符的 码点 //read() 如果返回 -1, 则代表文件读取完成 StringBuilder sb = new StringBuilder(); int len = -1; while ((len = reader.read()) != -1){ sb.append((char) len); } /* while (true) { int read = reader.read(); if (read == -1) break; sb.append((char)read); } */ System.out.println(sb); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { //数据读取完成后, 记得关闭资源 try { if (reader != null) reader.close(); //将reader设置为null reader = null; } catch (IOException e) { e.printStackTrace(); } } } @Test public void testReader2(){ FileReader reader = null; try { //通过文件路径,快速构建一个FileReader reader = new FileReader("D:\\abc\\m.ini"); //定义一个 char[] 数组, 负责 一次读取数据的长度 char[] data = new char[1024 * 8]; //代表读取的有效长度 int len = -1; StringBuilder sb = new StringBuilder(); //准备读取数据, read() 方法返回值 代表 读取的 真实长度 //如果发现read()返回-1, 代表读取结束 while ((len = reader.read(data)) != -1){ sb.append(new String(data, 0, len)); } System.out.println(sb); } catch (Exception e) { e.printStackTrace(); } finally { try { if(reader != null) { reader.close(); //将reader设置为null reader = null; } } catch (IOException e) { e.printStackTrace(); } } } @Test public void testReader3() throws Exception{ /** * Charset: 字符集--下面设置: UTF-8编码,可更改成 --> StandardCharsets.UTF_8 * encoding: 编码 * * try-with-resource (专门用来释放资源的) */ FileReader in =null; try { in = new FileReader("D:\\abc\\m.ini", Charset.forName("UTF-8")); char[] data = new char[1024 * 8]; StringBuilder sb = new StringBuilder(); int len = -1; while ( (len = in.read(data))!= -1 ){ sb.append(data,0,len); } System.out.println(sb); } finally { //关闭资源 if (in!=null) { in.close(); in = null; } } } @Test public void testReader4() throws Exception{ /** * Charset: 字符集--下面设置: UTF-8编码,可更改成 --> StandardCharsets.UTF_8 * encoding: 编码 * * try-with-resource (专门用来释放资源的) * try( ..定义需要自动关闭的对象. ) { * ... * 对象: 必须实现 Closeable 接口, 才能使用 try-with-resource * } */ //流中的默认编码采用 UTF-8 try (FileReader in = new FileReader("D:\\abc\\m.ini", Charset.forName("UTF-8"))){ char[] data = new char[1024 * 8]; StringBuilder sb = new StringBuilder(); int len = -1; while ( (len = in.read(data))!= -1 ){ sb.append(data,0,len); } System.out.println(sb); } } @Test public void testWriter(){ //创建一个输出流 //输出流 在写数据的时候, 必须要保证 父级路径是存在的, 文件名可以存在, 可以不存在 //文件名如果存在, 那么在写数据的时候, 会将原内容进行覆盖 //如果文件名不存在, 会自动创建一个文件 File file = new File("D://abc/a.txt"); //创建 file 父级路径 file.getParentFile().mkdirs(); // 如果设置编码, 代表设置的是文件的编码 try(FileWriter out = new FileWriter(file, Charset.forName("UTF-8"));){ //向流中写入数据 // write 如果传入的是int, 代表写入的字符的码点 // out.write(20013); //中 //将字符串转成流 byte[] bytes = "糖果".getBytes(); //将bytes流转成字符串 String s = new String(bytes, "GBK"); out.write(s); } catch (IOException e) { e.printStackTrace(); } } @Test public void testFileCopy(){ //将文件读入到内存 //将内存数据,写入新文件 try ( FileReader in = new FileReader("D:\\Program Files\\mysql-5.7.32\\my.ini"); FileWriter out = new FileWriter("D:/abc/my2.ini"); ) { //一次读取10个字符 char[] data = new char[10]; //负责接收读取的真实长度 int len = -1; while ((len = in.read(data)) != -1){ //读取到的数据 out.write(data, 0, len); } } catch (Exception e) { e.printStackTrace(); } } } -
创建文件,append 追加文件内容
-
package com.tang.io; import org.junit.Test; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class TestFileWriterAppend { @Test public void test(){ /** * 创建文件, 追加文件内容 */ File file = new File("D:/abc/test.txt"); //创建一个输出流 try ( //加一个 append 是否追加 FileWriter out = new FileWriter(file, true) ){ //将数据写入文件中 out.write("糖果,你好!\n"); out.write("糖果,加油!\n"); } catch (IOException e) { e.printStackTrace(); } } } -
BufferReader与BufferWriter
-
package com.tang.io; import org.junit.Test; import java.io.*; public class TestBuffered { @Test public void testBufferReader(){ //创建一个 BufferReader 对象, 默认缓冲8k //创建一个缓冲流, 缓冲流需要一个 流作为参数, 不能直接操作文件, 被称为过滤流 //能够直接操作文件的流 被称为节点流 try (BufferedReader in = new BufferedReader(new FileReader("D:\\abc\\my2.ini"))){ //一次性读取一行数据, 并返回字符串, readLine 如果返回null, 代表文件读取完成 //read(char[]) 如果返回 -1 , 代表读取完成, 读取的内容, 放入char数组中, 返回的 int 代表 读取的长度 //read() 如果返回 -1 , 代表读取完成, 返回 >=0, 代表读取的内容(码点) String str = null; //逐行读取数据 while ((str = in.readLine()) != null){ System.out.println(str); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @Test public void testBufferWriter(){ // try-with-resource 会自动关闭资源 try (BufferedWriter out = new BufferedWriter(new FileWriter("D:/abc/test/txt"))) { //向文件中, 输出数据 out.write("hello"); out.write("\thello"); //调用 flush 强制将数据写入磁盘 out.flush(); out.newLine();//换行 out.write("world"); //缓冲流, 自带缓冲效果, 作用主要是为了提高效率 } catch (IOException e) { e.printStackTrace(); } } } -
PrintWriter
-
package com.tang.io; import org.junit.Test; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; public class PrintWriterTest { @Test public void test() throws FileNotFoundException { /** * PrintWriter 既可以 直接操作文件, 也可以操作流(FileWriter, BufferedWriter, OutputStream) * PrintWriter 是 节点流, 也是过滤流, 字符流 */ try (PrintWriter out = new PrintWriter(new File("D:/abc/pw.txt"))) { //可以通过 write 将数据写入 //可以通过 println 将数据写入 out.write("hello"); out.println("world!"); out.printf("%d*%d=%d", 3, 5, 15); //刷出缓冲流 out.flush(); } } }
-
-
字节流
-
InputStream
-
OutputStream
-
package com.tang.io; import org.junit.Test; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class TestInputOutputStream { @Test public void testFileInputStream(){ //FileInputStream 输入流,节点流,字节流 FileInputStream in = null; FileOutputStream out = null; try{ in = new FileInputStream("D:\\abc\\my2.ini"); out = new FileOutputStream("D:\\abc\\my3.ini"); byte[] b = new byte[8]; int len = -1; //readAllBytes() 读取整个文件, 适合小文件 //read() 不传参, 代表一次读取一个字节, 返回该字节对应的码点, 汉字占用三个字节 //read(byte[]) 可以指定一次读取的最大字节数, 返回 读取的字节长度 while ( (len=in.read(b)) != -1 ){ out.write(b,0,len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { if (out != null) { out.close(); out = null; } } catch (IOException e) { e.printStackTrace(); } try { if (in != null){ in.close(); in = null; } } catch (IOException e) { e.printStackTrace(); } } } } -
BufferedInputStream与BufferedOutputStream
-
package com.tang.io; import org.junit.Test; import java.io.*; public class TestBufferedStream { @Test public void test(){ try(BufferedInputStream in = new BufferedInputStream(new FileInputStream("D:\\BianCheng\\ideaDown\\盗墓笔记·十年人间.m4a")); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream("D:/abc/盗墓笔记·十年人间.m4a")); ) { //进行数据的读写操作 byte[] data = new byte[8192]; int len = -1; while ( (len = in.read(data)) != -1 ){ out.write(data,0,len); //缓冲流, 需要调用 flush 强制写入数据 out.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } -
PrintStream
-
package com.tang.io; import org.junit.Test; import java.io.*; public class PrintStreamTest { @Test public void test(){ // PrintStream 输出流, 字节流, 是节点流也是过滤流 try(PrintStream out = new PrintStream("D:/abc/ps.jpg"); BufferedInputStream in = new BufferedInputStream(new FileInputStream("C:\\Users\\糖果\\Desktop\\Markdown学习\\糖果.ico")); ) { //将图片直接读入到内存 byte[] bytes = in.readAllBytes(); //数据从内存写入到新文件 out.write(bytes); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } -
InputStreamReader:字节-字符 转换流
-
读取配置文件→/test.properties:文件路径→项目下的→resource/test.properties
-
package com.tang.io; import org.junit.Test; import java.io.*; import java.util.Properties; public class InputStreamReaderTest { @Test public void test(){ try(FileInputStream fis = new FileInputStream("D:/abc/my2.ini"); //将字节流转成字符流 InputStreamReader isr = new InputStreamReader(fis); BufferedReader in = new BufferedReader(isr) ) { System.out.println(in.readLine()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } @Test public void testProperties() throws IOException { Properties p = new Properties(); // 读取文件 InputStream in = InputStreamReaderTest.class.getResourceAsStream("/test.properties"); //把 InputStream 转成 Reader, 可以设置读取的编码 InputStreamReader reader = new InputStreamReader(in, "UTF-8"); p.load(reader); String username = p.getProperty("username"); System.out.println(username); } }
-
-
-
功能
-
节点流
- 如,FileReader
-
过滤流
- 如,BufferReader
-
-
练习:拷贝文件、目录
-
package com.tang.file; import org.junit.Test; import java.io.*; public class ExTest { @Test public void test(){ //拷贝文件 //copyFile("D:\\BianCheng\\ideaDown\\风过谢桃花.m4a","D:\\abc"); //拷贝目录 copyDirectory("C:\\Users\\糖果\\Desktop\\Markdown学习","D:\\abc"); } /** * 拷贝文件 */ public void copyFile(String file, String desc){ this.copyFile(new File(file), new File(desc)); } private void copyFile(File file, File desc) { //如果 传入的类型不正确, 则抛出异常 if (!(file.isFile()) && desc.isDirectory()) throw new RuntimeException("传入的参数不正确"); //获取写入的路径 File target = new File(desc, file.getName()); //进行数据拷贝 try(BufferedInputStream in = new BufferedInputStream(new FileInputStream(file)); BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(target)) ) { //将file数据拷贝到target byte[] data = new byte[8192]; // 读取的有效长度 int len = -1; while ( (len = in.read(data)) != -1 ){ out.write(data,0,len); out.flush(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 拷贝目录 */ public void copyDirectory(String src, String desc) { this.copyDirectory(new File(src), new File(desc)); } private void copyDirectory(File src, File desc) { if (!(src.isDirectory())) throw new RuntimeException("传入的参数不正确"); //将 源目录中 所有的文件, 按照原来的路径 拷贝到 desc 目录中 //获取 src 目录 File target = new File(desc, src.getName()); //创建 target 目录 target.mkdirs(); //获取子目录 File[] files = src.listFiles(); for (File file : files) { //如果是文件, 则进行拷贝, 如果是目录, 则继续查找 if (file.isFile()){ copyFile(file,target); }else { copyDirectory(file, target); } } } @Test public void testPathSep(){ String path = "C:/abc/aaa"; String filename = "desktop"; //方式一: File file = new File(path, filename); System.out.println(file.getAbsolutePath()); //window 操作系统用 \ 分隔路径 //Linux 操作系统用 / 分隔路径 //在不同的操作系统下, File对路径的解析方式不一致 //代码在生成环境下, 一般是跑在Linux系统下的 //File.separator 分隔符,可以基于不同的操作系统, 获取不同的分隔符 //方式二: File file1 = new File(path); path = file1.getAbsolutePath(); String s = path + File.separator + filename; System.out.println(s); } }
装饰模式
-
父类
Person、子类Teacher、子类Student -
子类Teacher中:
-
有一个属性:类型是:父类
Person- 例如:
private Person person;
- 例如:
-
有若干个方法:参数列表中有一个参数类型是:父类
Person- 例如:
public viod test(Person person){}
- 例如:
-
调用Teacher中的方法时,就可以传入子类
Student的实例- 例如:
teacher.test(new Student());
- 例如:
-
zip文件的读写(不重要)
序列化
对象序列化
-
ObjectOutputStream 序列化:将内存中的Java对象写到磁盘的过程
-
ObjectInputStream 反序化:将磁盘上的文件内容读取到内存中并形成一个对象
-
Serializable 标记接口
-
serialVersionUID 序列化版本(非必须)
-
PS:反序列化时不调用构造方法
-
package com.tang.objSerial; import java.io.Serial; import java.io.Serializable; /** * Serializable 是一个标记接口 * * JVM 如果发现一个类时 Serializable, 那么就允许 这个类进行 对象序列化 */ public class User implements Serializable { @Serial private static final long serialVersionUID = 5930810682354677854L; private Integer id; private String username; /** * transient : 瞬时, 短暂的 * 用来定义 不需要进行 序列化的 字段 */ private transient String password; public User() { } public User(Integer id, String username, String password) { this.id = id; this.username = username; this.password = password; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } } ------------------------------------ package com.tang.objSerial; import org.junit.Test; import java.io.*; public class UserSerializer { //序列化 @Test public void test() throws IOException { /** * 将User对象,存储到磁盘的过程,被称为对象的序列化 * ObjectOutputStream 中的 writeObject(obj)方法 * 如果想要将一个对象, 进行序列化, 则必须让该对象实现 Serializable 接口 */ //创建一个序列化对象的流 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:/abc/user.txt")); //创建一个User User user = new User(); user.setId(1); user.setUsername("糖果"); user.setPassword("123456"); //将 user对象,存储到磁盘中 out.writeObject(user); //关闭流, 书写的不正规 out.close(); } //反序列化 @Test public void test2() throws Exception { ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:/abc/user.txt")); //将 user 从磁盘读入到内存 Object o = in.readObject(); if (o instanceof User){ User user = (User) o; System.out.println(user); } } }
JSON序列化
- 兼容其他语言
JSON特点
-
JSON 是编程语言中,一种轻量级的数据格式
-
Java中JSON包含的格式
-
模型对象(领域对象):只有属性和get、set方法
-
List/Set
-
Map
-
-
JSON序列化:将JSON格式的对象,转成字符串
-
JSON反序列化:将JSON格式的字符串,转成对象
处理JSON常用的库
fastjson
-
:下载地址
-
JSONArray
-
对模型进行序列化
-
package com.tang.json.fastjson; import com.alibaba.fastjson.JSONArray; import com.tang.objSerial.User; import org.junit.Test; public class FastJsonTest { //序列化 @Test public void testUserSerializer(){ User user = new User(); user.setId(1); user.setUsername("糖果"); user.setPassword("123456"); //将 User 模型对象, 序列化成 json 格式的字符串 String json = JSONArray.toJSONString(user); System.out.println(json); // {"id":1,"username":"糖果"} 是 JSON 格式的数据 // 键是一个字符串, 必须用 "" 引起来, 值如果是字符串, 也必须是双引号引起来 // 键和值 用 : 分隔, 多个值用逗号分隔 } //反序列化 @Test public void testUserDeSerializer(){ //定义一个 JSON 格式的字符串, 字符串中的键 必须和 要转成的对象中的 属性名保持一致 //属性名 指的是 set方法 String json = "{\"id\":1,\"username\":\"思雨\",\"password\":\"123456\"}"; //将该字符串, 转成 User 对象 User user = JSONArray.parseObject(json, User.class); System.out.println(user); } }
-
-
toJSONString(Object, SerializerFeature...)
- WriteMapNullValue 对空的键或者属性进行序列化显示
-
在对模型(POJO)进行序列化的时候,可以使用一些注解,进行精细的配置
-
@JSONField
-
name:设置(反)序列化的名字
-
format:进行格式化配置
-
serialize:是否进行序列化
-
deserialize:是否进行反序列化
-
alteranteNames:在反序列化的时候,设置多个别名进行匹配
-
package com.tang.json.fastjson; public class Computer { private String num; private String name; public String getNum() { return num; } public void setNum(String num) { this.num = num; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Computer{" + "num=" + num + ", name='" + name + '\'' + '}'; } } ---------------------------- package com.tang.json.fastjson; import com.alibaba.fastjson.annotation.JSONField; import java.util.Date; /** * Serializable 是一个标记接口 * * JVM 如果发现一个类时 Serializable, 那么就允许 这个类进行 对象序列化 */ public class User { private Integer id; @JSONField(name = "user_name", alternateNames = {"username",}) private String username; @JSONField(serialize = false)//不允许序列化 private String password; @JSONField(name = "create_time", format = "yyyy-MM-dd HH:mm:ss") private Date createTime; private Computer computer; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } //@JSONField(name = "user_name")//序列化 public String getUsername() { return username; } //@JSONField(name = "username")//反序列化 public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public Computer getComputer() { return computer; } public void setComputer(Computer computer) { this.computer = computer; } @Override public String toString() { return "User{" + "id=" + id + ", username='" + username + '\'' + ", password='" + password + '\'' + ", createTime=" + createTime + ", computer=" + computer + '}'; } } -------------------------------- package com.tang.json.fastjson; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.serializer.SerializerFeature; import org.junit.Test; import java.util.Date; public class ModelSerializerTest { /** * 模型的序列化与反序列化 */ @Test public void test(){ User user = new User(); user.setId(1); user.setUsername("糖果"); user.setCreateTime(new Date()); Computer computer = new Computer(); computer.setNum("001"); computer.setName("联想笔记本电脑"); user.setComputer(computer); //使用 fastjson 进行序列化 //SerializerFeature.WriteMapNullValue 显示空值 //SerializerFeature.WriteDateUseDateFormat 日期格式化(yyyy-MM-dd HH:mm:ss) //SerializerFeature.UseISO8601DateFormat 日期格式(ISO8601) //SerializerFeature.PrettyFormat 对输出的json进行格式化 String s = JSONArray.toJSONString(user, SerializerFeature.WriteMapNullValue, SerializerFeature.UseISO8601DateFormat,SerializerFeature.PrettyFormat); System.out.println(s); } @Test public void test2(){ //多行字符串 String text = """ { "computer":{ "name":"联想笔记本电脑", "num":"001" }, "create_time":"2022-06-05 16:45:52", "id":1, "user_name":"糖果", "password":"123456" } """; User user = JSONArray.parseObject(text, User.class); System.out.println(user); } }
-
-
-
parseObject(text, Class
clz):转换成对应的模型→模型对象(POJP) -
parseObject(text, TypeReference
):转换成对应的T类型,适用于复杂数据类型→Map -
对Map序列化
-
package com.tang.json.fastjson; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.serializer.SerializerFeature; import com.tang.objSerial.User; import org.junit.Test; import java.util.Date; import java.util.HashMap; import java.util.Map; public class TestMap { /** * 序列化 */ @Test public void test(){ Map<String, Object> map = new HashMap<>(); map.put("abc", 123); map.put("ttt",334); map.put("xxx",777); map.put("yyy",null); map.put("creat_time",new Date()); //序列化 String s = JSONArray.toJSONString(map, SerializerFeature.WriteMapNullValue, SerializerFeature.UseISO8601DateFormat, SerializerFeature.PrettyFormat); System.out.println(s); //日期格式化 //String s = JSONArray.toJSONStringWithDateFormat(map, "yyyy-MM-dd"); //日期格式化 /* String s1 = JSONArray.toJSONString(map, new ValueFilter() { @Override public Object process(Object o, String key, Object value) { if (value instanceof Date date) { value = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); } return value; } }); */ } /** * 反序列化 */ @Test public void test2(){ String json = """ { "user1":{ "id":2, "username":"李四", }, "xxx":{ "id":3, "username":"王五", } } """; Map<String, Object> map = JSONArray.parseObject(json); System.out.println(map); map.forEach((k,v)-> System.out.println(v.getClass().getName()));//JSONObject Map<String, User> map2 = JSONArray.parseObject(json, new TypeReference<Map<String, User>>() {}); System.out.println(map2); map2.forEach((k,v)-> System.out.println(v.getClass().getName()));//User } }
-
-
parseArray(text, Class
clz):将text转成List →List集合 -
对List集合序列化
-
package com.tang.json.fastjson; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.serializer.SerializerFeature; import org.junit.Test; import java.util.ArrayList; import java.util.Date; import java.util.List; public class TestList { /** * 序列化 反序列化 */ @Test public void test(){ List<User> users = new ArrayList<>(); User user1 = new User(); user1.setId(1); user1.setUsername("糖果"); user1.setPassword("123456"); Computer computer1 = new Computer(); computer1.setNum("001"); computer1.setName("联想"); user1.setComputer(computer1); users.add(user1); User user2 = new User(); user2.setId(2); user2.setUsername("思雨"); user2.setPassword("123456"); user2.setCreateTime(new Date()); Computer computer2 = new Computer(); computer2.setNum("001"); computer2.setName("戴尔"); user2.setComputer(computer2); users.add(user2); // 对 List 集合进行 // 序列化 String text = JSONArray.toJSONString(users, SerializerFeature.WriteMapNullValue, SerializerFeature.PrettyFormat); System.out.println(text); //多条记录的反序列化 /* List list1 = JSONArray.parseObject(text, List.class); System.out.println(list1);//JSONObject List<User> list2 = JSONArray.parseObject(text, new TypeReference<List<User>>() {}); System.out.println(list2);//User System.out.println(list2.get(0).getUsername()); */ List<User> users1 = JSONArray.parseArray(text, User.class); System.out.println(users1); System.out.println(users1.get(0).getUsername()); } }
-
-
-
JSONObject
-
继承Map<String, Object>
-
默认做为反序列化单条数据返回的结果
-
-
TypeReference:构建反序列化对应的数据类型
-
gson:
-
序列化、反序列化 都需要新建对象
-
new Gson(); 无法进行细节控制
-
new GsonBuilder().create(); 可以进行细节控制,详情看下面代码
-
-
toJson():序列化
-
fromJson():反序列化
-
package com.tang.objSerial.json.gson; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import com.tang.objSerial.json.fastjson.Computer; import com.tang.objSerial.json.fastjson.User; import org.junit.Test; import java.util.Date; import java.util.List; import java.util.Map; public class GsonTest { /** * gson模型序列化 */ @Test public void test(){ User user = new User(); user.setId(2); user.setUsername("思雨"); //user.setPassword("123456"); user.setCreateTime(new Date()); Computer computer2 = new Computer(); computer2.setNum("001"); computer2.setName("戴尔"); user.setComputer(computer2); /** * 创建一个 Gson对象 * 方式一: * Gson gson = new Gson();//无法进行细节控制 * 方式二: * Gson gson = new GsonBuilder().create(); * GsonBuilder中的细节处理: * 方法 setPrettyPrinting(): json格式化 * 方法 serializeNulls(): 显示空值 * 方法 setDateFormat(): 日期格式化 * 方法 excludeFieldsWithoutExposeAnnotation(): * 排除 没有 @Expose 的属性 */ //创建一个 Gson对象 //Gson gson1 = new Gson();//无法进行细节控制 //String s1 = gson1.toJson(user); //System.out.println(s1); //创建一个 Gson对象, 进行细节设置 Gson gson = new GsonBuilder() .setPrettyPrinting() //排除 没有 @Expose 的属性 //.excludeFieldsWithoutExposeAnnotation() .serializeNulls() .setDateFormat("yyyy-MM-dd") .create(); String s = gson.toJson(user); System.out.println(s); } /** * gson模型序列化 */ @Test public void test2(){ String json1 = """ { "id": 2, "username": "思雨", "createTime": "2022-06-06", "computer": { "num": "001", "name": "戴尔" } } """; String json2 = """ { "abc": { "id": 2, "username": "思雨", "createTime": "2022-06-06", "computer": { "num": "001", "name": "戴尔" } } } """; String json3 = """ [{ "id": 2, "username": "思雨", "createTime": "2022-06-06", "computer": { "num": "001", "name": "戴尔" } }] """; //对上述数据,转成 User 对象, 或者 Map Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd") .create(); //反序列化 //Map<String, Object> map1 = gson.fromJson(json1, Map.class);//不好用 //System.out.println(map1); // 模型 反序列化 User user = gson.fromJson(json1, User.class); System.out.println(user); // Map 反序列化 Map<String, User> map = gson.fromJson(json2, new TypeToken<Map<String, User>>(){}.getType()); System.out.println(map); System.out.println(map.get("abc").getClass()); // List 反序列化 List<User> list = gson.fromJson(json3, new TypeToken<List<User>>() {}.getType()); System.out.println(list); System.out.println(list.get(0).getClass()); } }
深拷贝和浅拷贝
- native修饰的方法,说明这个方法是由 操作系统,C++语言 来实现的
java克隆机制:
-
Object类中 提供了一个受保护的clone()方法
-
需要进行克隆的类,必须实现Cloneable接口
-
public class User implements Cloneable{}
-
-
需要进行克隆的类必须重写该方法,修饰符设置为public
-
@Override public Object clone() throws CloneNotSupportedException { return super.clone(); }
-
-
调用clone()方法,完成克隆,需要使用强转,返回指定类型
-
User u = (User) user.clone();
-
-
package com.tang.clone; import com.tang.json.fastjson.User; import org.junit.Test; public class TestClone { @Test public void test() throws CloneNotSupportedException { User user = new User(); user.setId(11); user.setUsername("糖果"); user.setPassword("123456"); //快速克隆一个用户 User u = (User) user.clone(); //修改克隆的用户名为李四 u.setUsername("思雨"); System.out.println(u.getUsername()); System.out.println(user.getUsername()); } }
深拷贝的实现机制
-
对象的序列化
-
json的序列化
-
利用序列化与反序列化
-
@Override public Object clone() throws CloneNotSupportedException { return JSON.parseObject(JSONArray.toJSONString(this), User.class); } -------------------------------------- package com.tang.clone; import com.tang.json.fastjson.Computer; import com.tang.json.fastjson.User; import org.junit.Test; public class TestClone { @Test public void test() throws CloneNotSupportedException { User user = new User(); user.setId(11); user.setUsername("糖果"); user.setPassword("123456"); Computer com = new Computer(); com.setName("联想"); com.setNum("0001"); user.setComputer(com); //快速克隆一个用户 User u = (User) user.clone(); //修改克隆的用户名为李四 u.setUsername("思雨"); u.getComputer().setNum("0002"); System.out.println(u == user); System.out.println(u.getComputer() == user.getComputer()); System.out.println(u.getUsername()); System.out.println(u.getComputer().getNum()); System.out.println(user.getUsername()); System.out.println(user.getComputer().getNum()); } }
-
commons-io工具包
-
FileUtils:主要是和File相关的操作
-
package com.tang.commons; import org.apache.commons.io.FileUtils; import org.junit.Test; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; public class FileUtilsTest { /** * 拷贝 移动 删除 */ @Test public void test1() throws IOException { //拷贝文件到文件 FileUtils.copyFile(new File("D:/abc/ps.jpg"), new File("D:/abc/1.jpg")); //拷贝文件到目录 FileUtils.copyFileToDirectory(new File("D:/abc/ps.jpg"), new File("D:/abc/cc")); //拷贝目录到目录 FileUtils.copyDirectoryToDirectory(new File("D:/abc/cc"), new File("D:/abc/dd")); //拷贝目录中的内容到目录 FileUtils.copyDirectory(new File("D:/abc/cc"), new File("D:/abc/ee")); //目录的内容移动目录 FileUtils.moveDirectory(new File("D:/abc/cc"), new File("D:/abc/mm")); //删除目录 FileUtils.deleteDirectory(new File("D:/abc/mm")); } /** * 读数据 */ @Test public void test2() throws IOException { //读取成 byte 数组 byte[] bytes = FileUtils.readFileToByteArray(new File("D:/abc/my3.ini")); System.out.println(bytes.length); //读取成 String String string = FileUtils.readFileToString(new File("D:/abc/my3.ini"), "utf-8"); System.out.println(string); //一行一行读取 List<String> list = FileUtils.readLines(new File("D:/abc/my3.ini"), StandardCharsets.UTF_8); System.out.println(list.get(0)); for (String s : list) { System.out.println(s); } } /** * 写数据 */ @Test public void test3() throws IOException { //读取成 byte 数组 byte[] bytes = FileUtils.readFileToByteArray(new File("D:/abc/my3.ini")); //byte 数组写入文件 FileUtils.writeByteArrayToFile(new File("D:/abc/222.ini"), bytes); //字符串写入文件 FileUtils.writeStringToFile(new File("D:/abc/www.ini"), "fafsadf糖果ffds", StandardCharsets.UTF_8); //按行写入 List<String> list =new ArrayList<>(); list.add("abc"); list.add("xyz"); FileUtils.writeLines(new File("D:/abc/www.ini"), "utf-8", list, true); } }
-
-
IOUtils:和IO流相关的操作
-
package com.tang.commons; import org.apache.commons.io.IOUtils; import org.junit.Test; import java.io.*; public class IOUtilsTest { @Test public void test() throws IOException { //文件输入流 InputStream in = new FileInputStream("D:\\abc\\test.txt"); //文件输出流 OutputStream out = new FileOutputStream("D:\\abc\\111.txt"); //读取成 byte数组 byte[] bytes = IOUtils.toByteArray(in); //byte 数组写入到文件 IOUtils.write(bytes,out); System.out.println(bytes.length); } }
-
Paths/Files工具类
-
Paths:常见API
- get(path):将对应地址转为Path
-
Files:常见API
-
readString(path):读返回字符串
-
readAllLines(path):返回List
-
readAllBytes(path):返回byte[]
-
write(path, byte[]):将byte[]信息写入path中
-
write(path, Iterable<? extends CharSequence>):
-
writeString(path, CharSequence):逐行写入字符串
-
probeContentType(path):根据文件猜测文件类型
-
package com.tang.Files; import org.junit.Test; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; public class FilesTest { @Test public void test() throws IOException { //通过路径快速构建一个 Path 对象 Path path = Paths.get("D:/abc/ps.jpg"); //猜测文件的类型 String s = Files.probeContentType(path); System.out.println(s); //使用 Files 工具类, 来操作文件 byte[] bytes = Files.readAllBytes(path); System.out.println(bytes.length); Files.write(Paths.get("D:/abc/a.jpg"),bytes); } }
-
IDEA快速生成serialVersionUID
设置:

Alt+Enter:快速生成
设置目的:防止别人窜改数据
博客园设置代码折叠


浙公网安备 33010602011771号