JavaIO流

IO流概述

在Java程序中,对于数据的输入/输出操作以“流(stream)”方式进行;Java提供了各种各样的“流”类,用以获取不同类的数据;程序中通过标准的方法输出或输入数据。Java的流类型一般位于java.io包中
数据源data source,提供原始数据的原始媒介。常见的:数据库、文件、其他程序、网络连接、IO设备(既可以做数据的源头,也可以做数据的目的地)
流是一个抽象、动态的概念,是一连串连续动态的数据集合。
数据元就像水箱,流就像水管中留着的水流,程序就是我们最终的用户。流是一个抽象、动态的概念,是一连串连续动态的数据集合。

IO流分类

  • 按流的方向分类:

    • 输入流:数据流向是数据源到程序(以InputStreamReader结尾的流)
    • 输出流:数据流向是程序到目的地(以OutPutStreamWriter结尾的流)
      输入输出流的划分是相对于程序而言的,并不是相对数据源
  • 按处理的数据单元分类:

    • 字节流:以字节为单位获取数据,命名上以Stream结尾的流一般是字节流,顶级类 InputStreamOutPutStream
    • 字符流:以字符为单位获取数据,命名上以ReaderWriter结尾的一般是字符流,顶级类ReaderWriter
  • 按处理对象不同分类:

    • 节点流:可以直接从数据源或目的地读写数据,如FileInputStreamFileReader
    • 处理流:不直接连接到数据源或目的地,是“处理流的流”,通过对其他流的处理提高程序的性能,如BufferedInputStream、BufferedReader等。处理流也叫包装流
      节点流处于IO操作的第一线,所有操作必须通过它们进行,处理流可以对节点流进行包装,提高性能或提高程序的灵活性

IO流体系结构

字节流

  • InputStreamOutPUtStream是Java语言中最基本的两个字节输入输出类,其他所有字节输出输入流类都继承这两个基类
  • 这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类
  • FilterInputStreamFilterOutPutStream是所有包装流的父类

字符流

  • ReaderWriter,Java语言中最基本的两个字符输入输出类
  • 其他所有字符输入输出流都继承自这两个基类
  • 这两个类都是抽象类,不能创建它们的实例,只能使用它们的子类
    字符流只适合读写文本之类的,不适合音频文件

File类的使用

  • File类用来代表文件和文件夹
  • 主要作用有两个:
    • 获取文件或者文件加的属性
    • 实现对文件、文件夹的创建和删除
方法 备注
file.isFile() 是否是文件
file.isDirectory() 是否是目录
file.exists() 是否存在
file.length() 文件大小(字节)
file.lastModified() 最后修改时间(毫秒值)
file.canRead() 是否可读
file.canWrite() 是否可写
file.canExecute() 是否可执行
file.getPath() 获取文件全路径
file.getParent() 获取文件父级目录
file.getParentFile() 获取父级文件
file.getAbsolutePath() 返回全路径
file.mkdir() 创建一级目录
file.mkdirs() 创建多级目录
file.createNewFile() 创建新文件
file.getName() 获取文件名称
file.list() 获取文件夹内文件的名称集合
file.listFiles() 获取文件夹内文件的集合
file.delete() 删除文件

文件流

文件字节流FileInputStreamFileOutPutStream

  • FileInputStreamFileOutPutStream是字节流,数据源和目的地是文件
  • 实现复制文件的功能
    • 复制文件需要分别创建一个输入流和输出流完成文件读写
    • 需要创建一个中转站,借助循环和中转站完成复制
    • 流使用完毕一定要关闭,这和垃圾回收没有关系
      代码如下
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      public class TestCopyFile {
      public static void main(String[] args) {
      try (FileInputStream fis = new FileInputStream("E:\\壁纸.zip");
      FileOutputStream fos = new FileOutputStream("E:\\壁纸2.zip")){
      byte[] bytes = new byte[1024];
      int len;
      while ((len = fis.read(bytes)) != -1){
      fos.write(bytes,0,len);
      }
      }catch (IOException e){
      e.printStackTrace();
      }
      }
      }

文件字符流FileReaderFileWriter

  • FileReaderFileWriter是字符流,数据源和目的地是文件
  • 实现复制文件的功能,代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class TestCopyFile1 {

    public static void main(String[] args) {
    try ( Reader rd = new FileReader("E:\\readme.txt");
    Writer wt = new FileWriter("E:\\readme2.txt");){
    char[] chars= new char[1024];
    int len;
    while ((len = rd.read(chars)) != -1){
    wt.write(chars,0,len);
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

    其实只有字节流,没有字符流。字符流的底层还是字节流,进行了封装转换可以更简单的来处理非英文字符
    字节流可以完成所有类型文件的复制(文本、音频、视频、图片、chm),字符流只能完成文本的复制(txt),doc不是文本文件,字符流一般只用来操作普通的文本文件

缓冲流

缓冲字节流BufferedInputStreamBufferedOutPutStream

  • 原理是在内存中创建一个缓冲区,默认大小是8192字节,输入流每次去缓冲区中获取,如果缓存区为空,会去磁盘一次读取8192字节,然后再根据自定义的中转站大小向输出流中转
  • 输出流也是默认创建一个8192的缓存区,等缓冲区满了或者最后关毕流的时候会一次性写入磁盘,减少于磁盘的交互,提升性能
  • 代码如下所示
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class TestCopyFile2 {

    public static void main(String[] args) {
    try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\照片.zip"));
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\照片2.zip"))){
    byte[] bytes = new byte[1024];
    int len;
    while ((len = bis.read(bytes)) != -1){
    bos.write(bytes,0,len);
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

缓冲字符流BufferedReaderBufferedWriter

  • 实现一次读取一行
  • 需要注意换行符问题
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class TestCopyFile3 {
    public static void main(String[] args) {
    try (BufferedReader br = new BufferedReader(new FileReader("E:\\readme.txt"));
    BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\readme2.txt"))){
    String str;
    while ((str = br.readLine()) != null){
    bw.write(str);
    bw.newLine();
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

数据流和对象流

之前使用文件流、缓冲流读取文件只能按照字节、数组方式读取,最方便的也是按行读取,能否很方便的实现各种基本类型和引用类型数据的读写,并保留其本身的类型。
数据流DataInputStreamDataOutPutStream和对象流ObjectInputStreamObjectOutPutStream可以解决这个问题,最大的优势就是提供了方便操作各种数据类型的方法,直接调用,简单方便

注意:

  • 只有字节流,没有字符流
  • 都是处理流,不是节点流
  • 数据流只能操作基本类型和字符串,对象流还可以操作对象
  • 写入的是二进制数据,无法直接通过记事本等查看
  • 写入的数据需要使用对应的输入输出流来读取

数据流DataInputStreamDataOutPutStream

  • DataInputStreamDataOutPutStream只能读取基本数据类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class DataStream {
public static void main(String[] args) {
// writer();
reader();
}

private static void writer(){
try (DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("E:\\readme.txt")));){
dos.writeInt(10);
dos.writeBoolean(true);
dos.writeUTF("今天的天气还是不错的");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

}
private static void reader(){
try (DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("E:\\readme.txt")));){
System.out.println(dis.readInt());
System.out.println(dis.readBoolean());
System.out.println(dis.readUTF());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

对象流ObjectInputStreamObjectOutPutStream

  • 可以读写基本数据类型和引用数据类型
  • 包含DataInputStreamDataOutPutStream的所有功能
  • 想要写入的对象类必须实现Serializable序列化接口
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public class ObjectStream {
    public static void main(String[] args) {
    // writer();
    reader();
    }
    private static void writer(){
    try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("E:\\readme.txt")));){
    oos.writeInt(10);
    oos.writeBoolean(true);
    oos.writeUTF("今天的天气还是不错的");
    oos.writeObject(new Date());
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    private static void reader(){
    try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("E:\\readme.txt")));){
    System.out.println(ois.readInt());
    System.out.println(ois.readBoolean());
    System.out.println(ois.readUTF());
    System.out.println(((Date)ois.readObject()).toLocaleString());
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }
    }
    }

序列化和反序列化

什么是序列化和反序列化

  • 序列化:Serialization,将对象的状态信息转换为可以存储或者传输的形式的过程
    • 对象(内存)—> 字节数组 字节序列(外存、网络)
  • 反序列化:DeSerialization 将字节数组转换成对象
    • 字节数组 字节序列(外存、网络)—–> 对象(内存)

什么时候需要序列化和反序列化

  • 存储或传输 比如存储到外存(硬盘)中,传输到网络

如何实现序列化和反序列化

  • 相应的类要实现Serializable接口
  • 静态变量是不参与序列化的
  • 用 transient 关键字修饰的字段也不参与序列化

其他流

打印流

  • PrintStreamPrintWriter
  • 只有输入流,没有输出流
  • System.outSystem.errPrintStream的实例变量
  • 代码如下所示: System.out.println()就是使用PrintStream做的打印
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class PrintStreamTest {

    public static void main(String[] args) {
    try (PrintStream ps = new PrintStream("E:\\readme.txt")){
    ps.println(12);
    ps.println(2.3);
    ps.println(true);
    ps.println("今天天气不错啊");
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    }
    }
    }

转换流

  • InputStreamReader和OutputStreamWriter
  • 实现字节流到字符流的转换,是适配器设计模式的应用
  • 只能从字节流转成字符流,可以带来处理字符的便利,没有字符流转换成字节流的转换流,因为没有这种需求
  • 将字节流转换成字符流,实现从键盘输入保存到文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class TestCopyFile4 {
    public static void main(String[] args) {
    try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    PrintStream bw = new PrintStream("E:\\readme2.txt")){
    String str;
    while (!"bye".equals(str = br.readLine())){
    bw.println(str);
    }
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

字节数组流

  • ByteArrayInputStreamByteArrayOutPutStream
  • 是节点流,数据源是字节数组,可以实现各种基本和引用数据类型与字节数组之间的相互转换

Java IO流的设计使用了装饰模式,动态组装流 ,可以减少子类的数量,是继承的一种替代方案

XML,可扩展标记语言

  • XML,Extensible Markup Language(可扩展标记语言),由SGML语言发展而来,允许用户自定义标签,可以将标签和内容有效分离。它主键演变成为一种跨平台的数据交互格式(一种在不同平台、不同系统之间的数据交换格式),一种轻量级的持久化方案(保存简单数据,无需使用数据库)

  • XML只是纯文本,只是一种独立于软件、硬件的数据存储和传输攻击,它可以对外提供一些信息,但由于C、Java这些编程语言不同,XML无法提供任何“动态行为”。

  • 和HTML提供预定义标签不同,开发者可以自定义任务标签,因此具有很强的扩张性,不同于HTML侧重于数据的展示,XML更加关注数据的存储和传输,不同于HTML可以使用浏览器来解析并显示,XML需要自行编写软件或程序,才能传递、接收、显示这个文档

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?xml version="1.0" encoding="utf-8" ?>
    <students>
    <student id = "001">
    <name>张三</name>
    <age>23</age>
    <score>98</score>
    </student>
    <student id="002">
    <name>李四</name>
    <age>24</age>
    <score>96</score>
    </student>
    </students>

    一个XML文件分为如下几个部分

  • 文档声明

    1
    <?xml version="1.0" encoding="utf-8" ?>
  • 元素

    <name>称为开始标签,</name>称为结束标签,”李四“表示标签的内容。
    开始标签、内容、结束标签组合成元素。元素是XML文档的主要部分,元素内容可以是普通文本,也可以是子元素,比如student元素的内部就是有多个子标签
    一个XML文档有且仅有一个根元素,比如students

  • 属性

    元素<student id="001">中的id就是属性名,001是属性值,属性值要使用双引号括起来,属性加载一个元素的开始开始标签上,用来对元素进行描述
    一个元素可以有多个属性,空格隔开
    属性没有先后顺序,同一个XML元素不允许有同名属性

  • 注释

    <!-- 学生信息 -->
    对XML内容进行解释说明的文字

  • CDATA标记、字符实体

    有时元素文本中会有一些特殊字符,比如<、>、"、&等,这些字符在XML文档结构本身中已经用到了,此时主要通过两种办法,实现正确解释这些特殊字符
    方法1,个别的特殊字符,可以使用字符实体替换

字符实体 特殊字符 含义
&lt; < 小于
&gt; > 大于
&amp; & 和号
&apos; ' 单引号
&aqot; " 双引号

严格地讲,在XML中仅有字符<&是非法的,单引号、双引号和大于号是合法的,但是把它们替换成实体引用是个好习惯
方法2,大量特殊字符可以使用CDATA标记来处理
CDATA标记中的所有字符都会被当作普通字符来处理,而不是XML标签
CDATA标记语法
<!CDATA[[要显示的字符]]>

格式良好的XML文档,遵循XML文档的基本规则

  • 元素正确嵌套
  • XML文件的第一行必须是xml声明
  • XML文件只能有一个根节点
  • 英文字符的大小写是有差异的
  • 开始的控制标记与结束的控制标记缺一不可
  • 属性值的设置必须被双引号包围起来

有效的XML文档

  • 首先必须是格式良好的(语法约束)
  • 使用DTD和XSD(XML Scheme)定义语义约束

内部DTD

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE students[
<!ELEMENT students (student+)>
<!ELEMENT student (name,age,score)>
<!ATTLIST student id CDATA #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT score (#PCDATA)>
]>
<students>
<student id="001">
<name>张三</name>
<age>23</age>
<score>98</score>
</student>
<student id="002">
<name>李四</name>
<age>24</age>
<score>96</score>
</student>
</students>

外部DTD

新建一个dtd文件,将内容复制进去
student.dtd

1
2
3
4
5
6
<!ELEMENT students (student+)>
<!ELEMENT student (name|age|score)+>
<!ATTLIST student id CDATA #REQUIRED>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT score (#PCDATA)>

在xml中引用
<!DOCTYPE 根元素 SYSTEM "外部DTD文件路径">

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE students SYSTEM "student.dtd">
<students>
<student id="001">
<age>23</age>
<name>张三</name>
<score>98</score>
</student>
<student id="002">
<name>李四</name>
<age>24</age>
<score>96</score>
</student>
</students>

公用DTD

  • 其实也算一种外部DTD,是有某个权威机构定制的,供特定行业或者公众使用
  • 公用DTD用过PUBLIC关键字引入,而不是SYSTEM
  • 另外还要再增加一个标识名
  • <!DOCTYPE 跟元素 PUBLIC "DTD标识名" "公用DTD的URI">

DOM解析XML

XML解析的四种方式

  • DOM和SAX是XML解析的两种规范,目前主流的XML解析器都会为DOM和SAX提供实现
  • 使用这两种技术解析XML比较繁琐,代码冗长,可读性也不高
  • 所以Java领域中又出现了两个开源XML解析器:DOM4J和JDOM
  • 其中DOM4J是面向接口编程
  • 而JDOM是面向实现编程
  • DOM4J比JDOM更灵活,性能表现也比较优异
  • DOM
    • 基于XML树结构
    • 比较耗资源
    • 适用于多次访问XML
  • SAX
    • 基于事件
    • 耗资源小
    • 适用于数据量比较大的XML
  • JDOM
    • 比DOM更快
    • JDOM仅使用具体类而不使用接口
  • DOM4J
    • 非常优秀的Java XML API
    • 性能优异
    • 功能强大
    • 开放源码

DOM:Document Object Model 文档对象模型

使用该技术解析XML文档时,会根据要操作的文档,构建一颗驻留内存中的树,然后就可以使用DOM接口来操作这棵树。
由于树是驻留再内存中,所以非常方便各种操作。
但是也因为这棵树包含了XML文档的所有内容,是比较耗费资源的,该方式适合小文档的解析、适合多次访问的文档的解析

SAX:Simple API for XML

是基于事件的解析,它是为了解决DOM解析的资源耗费而出现的。
SAX在解析一份XML文档时,会以次发出文档开始、元素开始、元素结束、文档结束等事件。
该方式不需要是事先调入整个文档,优势是占用资源少,内存耗费小,一般在解析数据量比较大的文档时采用该方式。

DOM4J:DOM for JAVA

开源XML解析工具,完全支持DOM、SAX机制,具有性能优异、功能强大和操作简单等特点。越来越多的Java软件都在使用DOM4J处理XML

JDOM:Java DOM

JDOM的目的是成为Java特定义文档模型。
行至半路,一部分人产生了新的想法,而这些想法又无法在JDOM中实现,干脆就从该项目中分离出来,单独取开发另外一套专属的XML API,这就是DOM4J。
因此,两者具有相同的设计目的,用法也非常相似。
从组中解决来看,JDOM的主要API以类为主,DOM4J的API以接口为主。

使用DOM解析XML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class TestDOM {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
//1.创建DOM解析器工厂
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//2.由DOM解析器工厂创建DOM解析器
DocumentBuilder db = dbf.newDocumentBuilder();
//3.由DOM解析器解析文档,生成DOM树
Document doc = db.parse("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student.xml");
NodeList nodeList = doc.getElementsByTagName("students");
Element root = (Element)nodeList.item(0);
NodeList students = root.getElementsByTagName("student");
for (int i = 0; i < students.getLength(); i++) {
Element item = (Element)students.item(i);
String id = item.getAttribute("id");
System.out.println(id);
NodeList childNodes = item.getChildNodes();
for (int j = 0; j < childNodes.getLength(); j++) {
Node node = childNodes.item(j);
if (node.getNodeType() == Node.ELEMENT_NODE){
Element element = (Element)node;
System.out.println(element.getNodeName()+"--->"+element.getTextContent());
}
}
}
}
}

缺点:

  • 前面三个步骤,每次都要书写一遍,能否封装好
  • getChildNodes()不仅包括Element,也包括空白形成的Text,遍历时需要进行筛选
  • getChildNodes()也包括注释,也包括外部DTD引用,大部分情况下并不是用户需要的

使用DOM4J解析XML

Attribute 定义了XML的属性
Node DOM4J树中所有节点的根接口
Branch 指包含子节点的节点,如元素(Element)和文档(Docuemnts)
Document 代表XML文档
Element 代表XML元素
CharacterData 所有文本元素的父接口,如CDATA、Comment、Text
CDATA 代表XML CDATA区域
Comment 代表XML注释内容
DocumentType 代表XML DOCTYPE声明
processingInstruction 代表XML处理指令
Attribute 代表XML元素的属性

添加DOM4J的依赖

1
2
3
4
5
 <dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>

DOM4J解析XML代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class TestDom4j1 {

public static void main(String[] args) throws DocumentException {
//1.根据XML文档创建DOM4J树
SAXReader reader = new SAXReader();
File file = new File("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student.xml");
Document document = reader.read(file);
//2.获取DOM4j树的跟节点students
Element rootElement = document.getRootElement();
//3.获取students的子节点student
//List<Element> elements = rootElement.elements();
Iterator<Element> it = rootElement.elementIterator();
//4.对student的属性和子节点进行解析
while (it.hasNext()) {
Element next = it.next();
// Attribute id = next.attribute("id");
// System.out.println(id.getName()+"-->"+id.getValue());
Iterator<Attribute> it2 = next.attributeIterator();
while (it2.hasNext()) {
Attribute attribute = it2.next();
System.out.println(attribute.getName() + "-->" + attribute.getValue());
}
List<Element> elements = next.elements();
for (Element element : elements) {
System.out.println(element.getName()+"--->"+element.getStringValue());
}
System.out.println();
}
}
}

DOM4J创建XML代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

public class TestDom4j2 {

public static void main(String[] args) throws IOException {
//1.创建一个DocumentFactory对象
//DocumentFactory factory = new DocumentFactory();
//2.使用DocumentFactory创建Document
//Document document = factory.createDocument();
Document document = DocumentHelper.createDocument();
document.addComment("学生信息");
//3.给Document指定一个跟节点students
Element rootElement = document.addElement("students");
//4.给students添加一个子节点student
Element element = rootElement.addElement("student");
//5.给student节点添加一个属性节点:id
element.addAttribute("id", "001");
//6.给student节点添加子节点:name age score
Element name = element.addElement("name");
name.addText("王五");
Element age = element.addElement("age");
age.addText("25");
Element score = element.addElement("score");
score.addText("98.5");
//7.将上面的DOM4J树写入文件
//默认写入的xml内容是不换行的,没有格式,可以创建一个格式
OutputFormat format = OutputFormat.createPrettyPrint();
Writer writer = new FileWriter("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
XMLWriter xmlWriter = new XMLWriter(writer,format);
xmlWriter.write(document);
xmlWriter.close();
}
}

DOM4J修改XML代码如下

在XML末尾添加子节点,默认就是在末尾添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class TestDom4j3 {

public static void main(String[] args) throws DocumentException, IOException {
//1.根据XML文档创建DOM4J树
SAXReader reader = new SAXReader();
File file = new File("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
Document document = reader.read(file);
//2.获取根节点
Element rootElement = document.getRootElement();
//3.给students添加一个子节点student
Element element = rootElement.addElement("student");
//4.给student节点添加一个属性节点:id
element.addAttribute("id", "002");
//5.给student节点添加子节点:name age score
Element name = element.addElement("name");
name.addText("李四");
Element age = element.addElement("age");
age.addText("56");
Element score = element.addElement("score");
score.addText("99.5");

//7.将上面的DOM4J树写入文件
//默认写入的xml内容是不换行的,没有格式,可以创建一个格式
OutputFormat format = OutputFormat.createPrettyPrint();
Writer writer = new FileWriter("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
XMLWriter xmlWriter = new XMLWriter(writer,format);
xmlWriter.write(document);
xmlWriter.close();
}
}

在XML中间插入节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class TestDom4j4 {

public static void main(String[] args) throws DocumentException, IOException {
//1.根据XML文档创建DOM4J树
SAXReader reader = new SAXReader();
File file = new File("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
Document document = reader.read(file);
//2.获取根节点
Element rootElement = document.getRootElement();
//获取根节点的所有子节点
List elements = rootElement.elements();
//3.新建一个子节点
Element element = DocumentHelper.createElement("student");
//4.给student节点添加一个属性节点:id
element.addAttribute("id", "003");
//5.给student节点添加子节点:name age score
Element name = element.addElement("name");
name.addText("张三");
Element age = element.addElement("age");
age.addText("78");
Element score = element.addElement("score");
score.addText("55.5");

//将新新建的子节点写入到节点树中
elements.add(1,element);

//7.将上面的DOM4J树写入文件
//默认写入的xml内容是不换行的,没有格式,可以创建一个格式
OutputFormat format = OutputFormat.createPrettyPrint();
Writer writer = new FileWriter("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
XMLWriter xmlWriter = new XMLWriter(writer,format);
xmlWriter.write(document);
xmlWriter.close();
}
}

根据条件删除某一个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class TestDom4j5 {

public static void main(String[] args) throws DocumentException, IOException {
//1.根据XML文档创建DOM4J树
SAXReader reader = new SAXReader();
File file = new File("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
Document document = reader.read(file);
//2.获取根节点
Element rootElement = document.getRootElement();
//获取根节点的所有子节点
List<Element> elements = rootElement.elements();
int index = -1;
for (int i = 0; i < elements.size(); i++) {
String id = elements.get(i).attribute("id").getValue();
if ("003".equals(id)) {
index = i;
break;
}
}
if (index == -1) {
System.out.println("没有找到需要删除的元素");
return;
} else {
elements.remove(index);
}
//7.将上面的DOM4J树写入文件
//默认写入的xml内容是不换行的,没有格式,可以创建一个格式
OutputFormat format = OutputFormat.createPrettyPrint();
Writer writer = new FileWriter("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
XMLWriter xmlWriter = new XMLWriter(writer, format);
xmlWriter.write(document);
xmlWriter.close();
}
}

根据条件修改某一个元素

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class TestDom4j6 {

public static void main(String[] args) throws DocumentException, IOException {
//1.根据XML文档创建DOM4J树
SAXReader reader = new SAXReader();
File file = new File("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
Document document = reader.read(file);
//2.获取根节点
Element rootElement = document.getRootElement();
//获取根节点的所有子节点
List<Element> elements = rootElement.elements();

for (int i = 0; i < elements.size(); i++) {
Element element = elements.get(i);
String id = element.attribute("id").getValue();
if ("001".equals(id)){
element.attribute("id").setValue("003");
Element name = element.element("name");
name.setText("天奇");
break;
}
}
//7.将上面的DOM4J树写入文件
//默认写入的xml内容是不换行的,没有格式,可以创建一个格式
OutputFormat format = OutputFormat.createPrettyPrint();
Writer writer = new FileWriter("E:\\project\\java\\leetcode\\src\\main\\java\\com\\ys\\io\\xml\\student1.xml");
XMLWriter xmlWriter = new XMLWriter(writer,format);
xmlWriter.write(document);
xmlWriter.close();
}
}