Java 高级文件处理

XML简介

  • XML基本概念

    • XML(eXtensible Markup Language)

    • 可扩展标记语言:意义+数据

    • 标签可自行定义,具有自我描述性

    • 纯文本表示,跨系统/平台/语言

    • W3C标准

  • 常规语法

    • 任何的起始标签都必须有一个结束标签

    • 简化写法,例如,可以写成

    • 大小写敏感

    • 每个文件都要有一个根元素

    • 标签必须按合适的顺序嵌套,不可错位

    • 所有的特性都必要有值,且在值的周围加上引号

    • 需要转义字符,如"<"需要用&lt;代替

      &lt; < 小于
      &gt; > 大于
      &amp; & 和号
      &apos; ' 单引号
      &quot; " 双引号
    • 注释:

  • XML扩展

    1. DTD(Document Type Definition)

      • 定义XML文档的结构
      • 使用一系列合法的元素来定义文档结构
      • 可嵌套在xml文档中,或者在xml中引用
    2. XML Shema(XSD,XML Schema Definition)

      • 定义XML文档的结构,DTD的继任者
      • 支持数据类型,可扩展,功能更完善、强大
      • 采用xml编写
    3. XSL

      • 扩展样式表语言(eXtensible Stylesheet Language)

      • XSL作用于XML,等同于CSS作用于HTML

      • 内容:

        XSLT:转换XML文档

        XPath:在XML文档中导航

        XSL-FO:格式化XML文档

XML解析(DOM方法)

  • XML解析方法

    1. 树结构

      • DOM:Document Object Model 文档对象模型,擅长(小规模)读/写
    2. 流结构

      • SAX:Simple API for XML 流机制解释器(推模式),擅长读
      • Stax:The Streaming API for XML 流机制解释器(拉模式),擅长读
  • DOM是W3C处理XML的标准API

    处理方式是将XML整个作为类似树结构的方式读入内存中以便操作及解析,方便修改。

    解析大数据量的XML文件,会遇到内存修理及程序崩溃的风险。

  • DOM类

    • DocumentBulider解析类,parse方法
    • Node节点主方法,getChildNodes返回一个NodeList
    • NodeList节点列表,每个元素是一个Node
    • Document文档根节点
    • Element标签节点元素(每个标签都是标签节点)
    • Text节点(包含在XML元素内的,都算Text节点)
    • Attr节点(每个属性节点)
  • 示例

    public class DomReader {
        public static void main(String[] args) {
            recursiveTraverse();
            System.out.println("======分割线=======");
            traverseBySearch();
        }
    
        public static void recursiveTraverse() {
            try {
                // 采用DOM解析xml文件
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                DocumentBuilder db = dbf.newDocumentBuilder();
                Document document = db.parse("user.xml");
    
                // 获取所有的一级节点
                NodeList usersList = document.getChildNodes();
                System.out.println("The 1st level length:"+usersList.getLength());
    
                for(int i=0;i<usersList.getLength();i++) {
                    Node users = usersList.item(i);
                    NodeList userList = users.getChildNodes();
                    System.out.println("The 2nd level length:"+userList.getLength());
    
                    for(int j=0;j<userList.getLength();j++) {
                        Node user = userList.item(j);
                        if (user.getNodeType() == Node.ELEMENT_NODE) {
                            NodeList metaList = user.getChildNodes();
                            System.out.println("The 3rd level length:"+metaList.getLength());
    
                            for (int k=0;k<metaList.getLength();k++) {
                                Node meta = metaList.item(k);
                                if (meta.getNodeType() == Node.ELEMENT_NODE) {
                                    System.out.println(meta.getNodeName()+":"+meta.getTextContent());
                                }
                            }
    
                            System.out.println();
                        }
                    }
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static void traverseBySearch() {
            try {
                // 采用DOM解析xml文件
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                DocumentBuilder db = dbf.newDocumentBuilder();
                Document document = db.parse("user.xml");
    
                Element rootElement = document.getDocumentElement();
                NodeList nodeList = rootElement.getElementsByTagName("name");
                if (nodeList != null) {
                    for (int i=0;i<nodeList.getLength();i++) {
                        Element element = (Element) nodeList.item(i);
                        System.out.println(element.getNodeName()+"="+element.getTextContent());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public class DomWriter {
        public static void main(String[] args) {
            try {
                DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    
                // 创建一个Document节点
                Document document = documentBuilder.newDocument();
                if (document != null) {
                    Element docx = document.createElement("document");
                    Element element = document.createElement("element");
                    element.setAttribute("type","paragraph");
                    element.setAttribute("alignment","left");
    
                    Element object = document.createElement("object");
                    object.setAttribute("type","text");
    
                    Element text = document.createElement("text");
                    text.appendChild(document.createTextNode("abcdefg"));
                    Element bold = document.createElement("bold");
                    bold.appendChild(document.createTextNode("true"));
    
                    object.appendChild(text);
                    object.appendChild(bold);
                    element.appendChild(object);
                    docx.appendChild(element);
                    document.appendChild(docx);
    
                    TransformerFactory transformerFactory = TransformerFactory.newInstance();
                    Transformer transformer = transformerFactory.newTransformer();
                    DOMSource source = new DOMSource(document);
    
                    // 定义目标文件
                    File file = new File("dom_result.xml");
                    StreamResult result = new StreamResult(file);
    
                    //将xml内容写入到文件中
                    transformer.transform(source,result);
    
                    System.out.println("write xml file successfully");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

XML解析(SAX方法)

  • Simple API for XML

    • 采用事件/流模型来解析XML文档,更快速、更轻量
    • 有选择的解析和访问,不像DOM加载整个文档,内存要求较低
    • SAX对XML文档的解析为一次性读取,不创建/不存储文档对象,很难同时访问文档中的多处数据
    • 推模型。当它每发现一个节点就引发一个事件,而我们需要编写这些事件的处理程序。关键类:DefaultHandler
    • SAX的五个回调方法:
      1. startDocument 文档开始解析;
      2. endDocument文档结束解析;
      3. startElement开始访问元素;
      4. endElement结束访问元素;
      5. characters访问元素正文
  • 示例

    public class SAXReader {
        public static void main(String[] args) throws SAXException, IOException {
            XMLReader parser = XMLReaderFactory.createXMLReader();
            BookHandler bookHandler = new BookHandler();
            parser.setContentHandler(bookHandler);
            parser.parse("books.xml");
            System.out.println(bookHandler.getNameList());
        }
    }
    
    class BookHandler extends DefaultHandler {
        private List<String> nameList;
        private boolean title = false;
    
        public List<String> getNameList() {
            return nameList;
        }
    
        @Override
        public void startDocument() throws SAXException {
            System.out.println("Start parsing document...");
            nameList = new ArrayList<String>();
        }
    
        @Override
        public void endDocument() throws SAXException {
            System.out.println("End");
        }
    
        @Override
        public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
            if (qName.equals("title")) {
                title=true;
            }
        }
    
        @Override
        public void endElement(String uri, String localName, String qName) throws SAXException {
            if(title) {
                title=false;
            }
        }
    
        @Override
        public void characters(char[] ch, int start, int length) throws SAXException {
            if(title) {
                String bookTitle = new String(ch, start, length);
                System.out.println("Book title: "+bookTitle);
                nameList.add(bookTitle);
            }
        }
    }
    

XML解析(Stax方法)

  • Streaming API for XML

    • 流模型中的拉模型
    • 在遍历文档时,会把感兴趣的部分从读拉取器中拉出,不需要引发事件,允许我们选择性地处理节点。这大大提高了灵活性,以及整体效率。
    • 两套处理API
      1. 基础指针的API,XMLStreamReader
      2. 基于迭代器的API,XMLEventReader
  • 示例

    public class StaxReader {
        public static void main(String[] args) {
            StaxReader.readByStream();
            System.out.println("======分割线======");
            StaxReader.readByEvent();
        }
    
        // 流模式
        public static void readByStream() {
            String xmlFile = "books.xml";
            XMLInputFactory factory = XMLInputFactory.newFactory();
            XMLStreamReader streamReader = null;
            try {
                streamReader=factory.createXMLStreamReader(new FileReader(xmlFile));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (XMLStreamException e) {
                e.printStackTrace();
            }
    
            // 基于指针遍历
            try {
                while (streamReader.hasNext()) {
                    int event = streamReader.next();
                    if (event== XMLStreamConstants.START_ELEMENT) {
                        if("title".equalsIgnoreCase(streamReader.getLocalName())) {
                            System.out.println("title:" + streamReader.getElementText());
                        }
                    }
                }
                streamReader.close();
            } catch (XMLStreamException e) {
                e.printStackTrace();
            }
        }
    
        // 事件模式
        public static void readByEvent() {
            String xmlFile = "books.xml";
            XMLInputFactory factory = XMLInputFactory.newFactory();
            boolean titleFlag = false;
            try {
                // 创建基于迭代器的事件读取器对象
                XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(xmlFile));
    
                // 遍历Event迭代器
                while (eventReader.hasNext()) {
                    XMLEvent event=eventReader.nextEvent();
                    // 如果事件对象是元素的开始
                    if (event.isStartElement()) {
                        // 转换成开始元素事件对象
                        StartElement start = event.asStartElement();
    
                        // 打印元素标签的本地名称
                        String name = start.getName().getLocalPart();
                        // System.out.println(name);
                        if (name.equals("title")) {
                            titleFlag = true;
                            System.out.print("title:");
                        }
    
                        // 取得所有属性
                        Iterator attrs = start.getAttributes();
                        while (attrs.hasNext()) {
                            // 打印所有属性信息
                            Attribute attr = (Attribute)attrs.next();
                            // System.out.println(":"+attr.getName().getLocalPart()+"="+attr.getValue());
                        }
                        // System.out.println();
                    }
    
                    // 如果事件对象是正文
                    if (event.isCharacters()) {
                        String s = event.asCharacters().getData();
                        if (s !=null && s.trim().length()>0 && titleFlag) {
                            System.out.println(s.trim());
                        }
                    }
    
                    // 如果事件对象时元素的结束
                    if (event.isEndElement()) {
                        EndElement end = event.asEndElement();
                        String name = end.getName().getLocalPart();
                        if (name.equals("title")) {
                            titleFlag = false;
                        }
                    }
                }
                eventReader.close();
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (XMLStreamException e) {
                e.printStackTrace();
            }
        }
    }
    

Json简介及解析

  • JSON

    • JavaScript Object Notation, JS对象表示法
    • 是一种轻量级的数据交换格式
    • 类似XML,更小、更快、更易解析
    • 最早用于Javascript,容易解析,最后推广到全语言
    • 尽管使用Javascript语法,但是独立于编程语言
  • JSONObject和JSONArray

    • 名称/值对。如“firstName":"Jhon”
    • JSON对象:{'name':'Jo', 'email':'a@b.com'}
    • 数据在键值对中
    • 数据由逗号分隔
    • 花括号保存对象
  • JSON数组

    • 方括号保存数组

      [{'name':'Jo', 'email':'a@b.com'}, {'name':'Jo', 'email':'a@b.com'}]

  • Java的JSON处理

    • org.json:JSON官方推荐的解析类

      简单易用,通用性强,复杂功能欠缺

    • GSON:Google出品

      基于反射,可以实现JSON对象、JSON字符串和Java对象互转

    • Jackson:号称最快的JSON处理器

      简单易用,社区更新和发布速度比较快

  • JSON主要用途

    • JSON生成
    • JSON解析
    • JSON校验
    • 和Java Bean对象进行互解析
      • 具有一个无参的构造函数
      • 可以包括多个属性,所有属性都是private
      • 每个属性都有相应的Getter/Setter方法
      • Java Bean用于封装数据,又可称为POJO(Plain Old Java Object)
  • 示例

    org.json

    public class OrgJsonTest {
        public static void main(String[] args) {
            testJsonObject();
            System.out.println("======分割线======");
            testJsonFile();
        }
    
        public static void testJsonObject() {
            // 构造对象
            Person p = new Person();
            p.setName("Tom");
            p.setAge(20);
            p.setScores(Arrays.asList(60,70,80));
    
            // 构造JSONObject对象
            JSONObject obj = new JSONObject();
            obj.put("name",p.getName());
            obj.put("age",p.getAge());
            obj.put("scores",p.getScores());
    
            System.out.println(obj);
            System.out.println("name: "+obj.getString("name"));
            System.out.println("age: "+obj.getInt("age"));
            System.out.println("scores: "+obj.getJSONArray("scores"));
        }
    
        public static void testJsonFile() {
            File file = new File("books.json");
            try {
                FileReader reader = new FileReader(file);
                // 读取文件内容到JSONObject对象中
                int fileLen = (int)file.length();
                char[] chars = new char[fileLen];
                reader.read(chars);
                String s = String.valueOf(chars);
                JSONObject jsonObject = new JSONObject(s);
    
                // 开始解析JSONObject对象
                JSONArray books = jsonObject.getJSONArray("books");
                List<Book> bookList = new ArrayList<>();
    
                for(Object book:books) {
                    // 获取单个JSONObject对象
                    JSONObject bookObject = (JSONObject)book;
                    Book book1 = new Book();
                    book1.setAuthor(bookObject.getString("author"));
                    book1.setYear(bookObject.getString("year"));
                    book1.setTitle(bookObject.getString("title"));
                    book1.setPrice(bookObject.getInt("price"));
                    book1.setCategory(bookObject.getString("category"));
                    bookList.add(book1);
                }
    
                for(Book book:bookList) {
                    System.out.println(book.getAuthor()+", "+book.getTitle());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    Gson

    public class GsonTest {
        public static void main(String[] args) {
            testJsonObject();
            System.out.println("======分割线======");
            testJsonFile();
        }
    
        public static void testJsonObject() {
            //构造对象
            Person p = new Person();
            p.setName("Tom");
            p.setAge(20);
            p.setScores(Arrays.asList(60,70,80));
    
            //从Java对象到JSON字符串
            Gson gson = new Gson();
            String s = gson.toJson(p);
            System.out.println(s);
    
            //从JSON字符串到Java对象
            Person p2 = gson.fromJson(s, Person.class);
            System.out.println(p2.getName());
            System.out.println(p2.getAge());
            System.out.println(p2.getScores());
    
            //调用GSON的JsonObject
            JsonObject json = gson.toJsonTree(p).getAsJsonObject();
            System.out.println(json.get("name"));
            System.out.println(json.get("age"));
            System.out.println(json.get("scores"));
        }
    
        public static void testJsonFile() {
            Gson gson = new Gson();
            File file = new File("books2.json");
    
            try {
                FileReader reader = new FileReader(file);
                List<Book> books = gson.fromJson(reader,new TypeToken<List<Book>>(){}.getType());
                for(Book book:books) {
                    System.out.println(book.getAuthor()+", "+book.getTitle());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

JSON和XML比较

  • 都是数据交换格式,可读性强,可扩展性高
  • 大部分的情况下,JSON更具优势(编码简单,转换方便),而且JSON字符串长度一般小于XML,传输效率更高
  • XML更加注重标签和顺序
  • JSON会丢失顺序信息
原文地址:https://www.cnblogs.com/hunter-w/p/13882336.html