热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

XML学习笔记(四):xml解析详解以及使用DOM和SAX解析XML:

一、XML解析的简介1、一般来说xml解析的方式有两种,Dom与SAX,且各有优缺点。pull是第三种方法见:pull解析XML1)DOM:dom对象树①、整个XML放入内存,转换为Document对

一、XML解析的简介

1、一般来说xml解析的方式有两种,Dom与SAX,且各有优缺点。pull是第三种方法见:pull解析XML

1)DOM:dom对象树

①、整个XML放入内存,转换为Document对象;

②、每个元素,转换成Element对象

③、文本,转换成Text对象

④、属性,转换成Attribute对象

优缺点:元素的CRUD比较简单,但是内存消耗大,大的xml文档不适合。


补充:内存不足时,可以修改参数,调整JVM的内存大小

 1、java.lang.OutOfMemoryError: Java heap space 堆内存不足
 2、单个main方法运行时,修改VM Arguments参数为  -Xmx80m  。80为随意修改。

 3、运行程序时,可以修改eclipse的安装目录中 eclipse.ini文件的参数值: -Xmx768m 。


2)SAX:

对于整个XML文档,从上往下读,读取一行,解析一行。

优缺点:不影响内存,但是不适合对文档作CRUD。


2、Java提供两块API与xml解析有关:

1)一为Jaxp:提供了dom与sax解析xml的方法(完全可以被Jdom或是Dom4J代替);

2)二是jaxb:主要是使用注解处理xml与JavaBean的映射,在WebService中被广泛应用。


3、我们在实际开发环境中,对于XML的工作一般可以总结为几类(都会解决):

1)配置文件的解析:自己本地的文件解析;(XML学习笔记(五):使用 jdom和dom4j 解析XML

2)数据交互:与第三方平台如淘宝、天猫、网易等的交互数据的解析;(XML学习笔记(六):Jaxb负责xml与javaBean映射

3)模板数据:如短息或是邮件模板;


4、FreeMarker和Apache有一套不错的api可以用于XML的解析,分别为freemarker.template.Template类和org.apache.velocity.VelocityContext类。(XML学习笔记(七):使用freemark与apache填充xml模板)


二、Jaxp的Dom和Sax

1、XML文件存放在名叫resources的系统source filder文件夹内:命名为Request.xml




SAM-SHO
28






牙膏
100
刷牙用的






file
d:/log.txt


filegg4
d:/log.txtgg4




file2
d:/log.txt2






file1
d:/log.txt1













2、使用Dom和Sax解析Xml,其其开始的步骤基本都是统一的:

1)都是创建工厂、获取解析器、获取文件、解析文件。

2)然后不同之处就开始了。Dom是直接取转换的对象,而Sax是在自定义的Handler中逐个处理获取Element。

3)解析的代码都比较简单,直接上实例代码。


(一)DOM

1、获取XML文档的元素、属性、文本信息、创建新的元素并写入文档。方法如下:

1)获取工厂、解析器等为固定步骤,获取xml文档的方法有多种,这边使用classloader方式。

2)整个XML文档被解析成一个Document对象。

3)获取元素:document.getElementsByTagName("appnt"), 可以获取名为appnt的元素。这边注意,Node为一切元素的父类。

4)getNodeName():获元素的名称;getTextContent():获取元素的文本值;getAttribute():获取元素的属性值

5)添加元素的用法是固定的,

①、先创建元素,并添加属性与文本内容,方法为createElement("元素名称");setAttribute();setTextContent()

②、规定放入的位置,如放入根节点:root.appendChild("创建的元素"),root为根节点。

③、固定使用Transformer类把创建的新元素,写入文件。

/**
* 通过DOM获取xml文档
*/
public void getXMLFromDom() {

try {

// 1-: 获得dom解析器工厂(工作的作用是用于创建具体的解析器)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

// 2-:获得具体的dom解析器
DocumentBuilder db = dbf.newDocumentBuilder();

// 3-: 解析一个xml文档,获得Document对象
// 利用classloader加载xml文件,文件的位置很重要
InputStream input = this.getClass().getClassLoader().getResourceAsStream("Request.xml");
Document document = db.parse(input);


// 4-通过元素名,得到某个元素

// 4-1 得到元素
NodeList appntElement = document.getElementsByTagName("appnt");
Node appnt = appntElement.item(0);// 得到第一个
String name = appnt.getNodeName();// 得到元素的名称
logger.debug("元素的名称 : " + name);// appnt

// 4-2 得到元素所有子元素
NodeList appntChildren = appnt.getChildNodes();

// 4-3 得到元素下元素
Node appnt_name = appntChildren.item(1);
logger.debug("元素下子元素的名称 : " + appnt_name.getNodeName());
logger.debug("元素下子元素的value : " + appnt_name.getTextContent());

// 4-4 得到元素下元素
// 中间有text类的内容也会被解析,所以这边1跳转到了3
// item(2)的话,会输出#Text,是指在#Text中间的文本信息
Node appnt_age = appntChildren.item(3);
logger.debug("元素下子元素的名称 : " + appnt_age.getNodeName());
logger.debug("元素下子元素的value : " + appnt_age.getTextContent());


// 5-获取属性值
Element insuredElement = (Element) document.getElementsByTagName("insured").item(0);
String insuredName = insuredElement.getAttribute("name");
String insuredAge = insuredElement.getAttribute("age");

logger.debug("元素的name属性为: " + insuredName +" |age属性为" + insuredAge);


// 6-添加节点元素

// 6-1 新建元素
Element element = document.createElement("新建标签");
element.setAttribute("属性", "10块");
element.setTextContent("我是动态新建的元素");

// 6-2 放入根节点元素
Element root = document.getDocumentElement();//获取根节点
root.appendChild(element);//新建的元素放入根节点元素

// 6-3 写入文件,需要使用 TransformerFactory 固定写法
TransformerFactory tff = TransformerFactory.newInstance();
Transformer transformer = tff.newTransformer();

// 写出去
DOMSource domSource = new DOMSource(document);
Result result = new StreamResult(new FileOutputStream("resources/Request.xml"));
transformer.transform(domSource, result);

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}

}


2、使用DOM解析整个XML文档,会使用递归方法。代码如下:

1)获取解析器等步骤都是一致的,这边使用文件流获取XML文件。

2)获取根节点后,使用递归获取根节点下的所有元素。方法为listChildrenNodes("根元素")

3)由于DOM解析的时候,会把空的文本信息Text也解析,我们可以预判断,处理掉。getChildNodes()可以得到子元素。

/**
* Dom解析整个XML文档
*
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public void domXML() throws ParserConfigurationException, SAXException, IOException {
// 1-: 获得dom解析器工厂(工作的作用是用于创建具体的解析器)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

// 2-:获得具体的dom解析器
DocumentBuilder db = dbf.newDocumentBuilder();

// 3-: 解析一个xml文档,获得Document对象InputStream
Document document = db.parse(new File("resources/Request.xml"));

// 4-得到根节点
Element requestElement = document.getDocumentElement();
logger.debug("得到根节点: " + requestElement.getNodeName());

// 需要使用递归
listChildrenNodes(requestElement);
}

/**
* 递归方法 打印的时候会有每个Text对象,会处理掉
*
* @param root
*/
private void listChildrenNodes(Node root) {

// 先判断一步, 把Text对象过滤掉
if (root instanceof Element) {
logger.debug("节点的名字为: " + root.getNodeName());
}

NodeList childrenLists = root.getChildNodes();
for (int i = 0; i Node child = childrenLists.item(i);
// 递归调用
listChildrenNodes(child);
}

}

3、以上两个方法分别简单处理了jaxp的Dom解析XML的实例,在main方法中调用即可运行,全部代码为:

/**
* 一、XML的解析方式有2中方式:(现在还有poi解析)
* 1、DOM解析:dom对象树
* 1)整个XML放入内存,转换为Document对象;
* 2)每个元素,转换成Element对象
* 3)文本,转换成Text对象
* 4)属性,转换成Attribute对象
*
* 优缺点:元素的CRUD比较简单,但是内存消耗大,大的xml文档不适合。
*
*
* 2、SAX解析:从上往下读,读取一行,解析一行
*
* 优缺点:不影响内存,但是不适合对文档作CRUD。
*
* 二、XML解析开发包
* 1、jaxp
* 2、jDom
* 3、Dom4j
*
*
* 三、调整JVM的内存大小
* 1、java.lang.OutOfMemoryError: Java heap space 堆内存不足
* 2、 固定为64M
* 3、 -Xmx80m 修改VM Arguments
*
*/

package xml.code.base;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
*
* DomJaxpXML.java
*
* @title Dom解析XML
* @description
* @author SAM-SHO
* @Date 2014-10-12
*/
public class DomJaxpXML {

private static Logger logger = Logger.getLogger(DomJaxpXML.class);

public static void main(String[] args) throws Exception {

// ************************调整JVM 内存大小
// java.lang.OutOfMemoryError: Java heap space 堆内存不足
// 固定为64M
// -Xmx80m 修改VM Arguments
// byte[] b = new byte[1024 * 1024 * 70];

DomJaxpXML JavapXML = new DomJaxpXML();

// 通过Dom获取XML
JavapXML.getXMLFromDom();

JavapXML.domXML();
}

/**
* 通过DOM获取xml文档
*/
public void getXMLFromDom() {

try {

// 1-: 获得dom解析器工厂(工作的作用是用于创建具体的解析器)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

// 2-:获得具体的dom解析器
DocumentBuilder db = dbf.newDocumentBuilder();

// 3-: 解析一个xml文档,获得Document对象
// 利用classloader加载xml文件,文件的位置很重要
InputStream input = this.getClass().getClassLoader().getResourceAsStream("Request.xml");
Document document = db.parse(input);


// 4-通过元素名,得到某个元素

// 4-1 得到元素
NodeList appntElement = document.getElementsByTagName("appnt");
Node appnt = appntElement.item(0);// 得到第一个
String name = appnt.getNodeName();// 得到元素的名称
logger.debug("元素的名称 : " + name);// appnt

// 4-2 得到元素所有子元素
NodeList appntChildren = appnt.getChildNodes();

// 4-3 得到元素下元素
Node appnt_name = appntChildren.item(1);
logger.debug("元素下子元素的名称 : " + appnt_name.getNodeName());
logger.debug("元素下子元素的value : " + appnt_name.getTextContent());

// 4-4 得到元素下元素
// 中间有text类的内容也会被解析,所以这边1跳转到了3
// item(2)的话,会输出#Text,是指在#Text中间的文本信息
Node appnt_age = appntChildren.item(3);
logger.debug("元素下子元素的名称 : " + appnt_age.getNodeName());
logger.debug("元素下子元素的value : " + appnt_age.getTextContent());


// 5-获取属性值
Element insuredElement = (Element) document.getElementsByTagName("insured").item(0);
String insuredName = insuredElement.getAttribute("name");
String insuredAge = insuredElement.getAttribute("age");

logger.debug("元素的name属性为: " + insuredName +" |age属性为" + insuredAge);


// 6-添加节点元素

// 6-1 新建元素
Element element = document.createElement("新建标签");
element.setAttribute("属性", "10块");
element.setTextContent("我是动态新建的元素");

// 6-2 放入根节点元素
Element root = document.getDocumentElement();//获取根节点
root.appendChild(element);//新建的元素放入根节点元素

// 6-3 写入文件,需要使用 TransformerFactory 固定写法
TransformerFactory tff = TransformerFactory.newInstance();
Transformer transformer = tff.newTransformer();

// 写出去
DOMSource domSource = new DOMSource(document);
Result result = new StreamResult(new FileOutputStream("resources/Request.xml"));
transformer.transform(domSource, result);

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}

}

/**
* Dom解析整个XML文档
*
* @throws ParserConfigurationException
* @throws SAXException
* @throws IOException
*/
public void domXML() throws ParserConfigurationException, SAXException, IOException {
// 1-: 获得dom解析器工厂(工作的作用是用于创建具体的解析器)
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

// 2-:获得具体的dom解析器
DocumentBuilder db = dbf.newDocumentBuilder();

// 3-: 解析一个xml文档,获得Document对象InputStream
Document document = db.parse(new File("resources/Request.xml"));

// 4-得到根节点
Element requestElement = document.getDocumentElement();
logger.debug("得到根节点: " + requestElement.getNodeName());

// 需要使用递归
listChildrenNodes(requestElement);
}

/**
* 递归方法 打印的时候会有每个Text对象,会处理掉
*
* @param root
*/
private void listChildrenNodes(Node root) {

// 先判断一步, 把Text对象过滤掉
if (root instanceof Element) {
logger.debug("节点的名字为: " + root.getNodeName());
}

NodeList childrenLists = root.getChildNodes();
for (int i = 0; i Node child = childrenLists.item(i);
// 递归调用
listChildrenNodes(child);
}

}

}

(二)SAX

1、 SAX采用事件处理的方式解析XML文件,涉及两个部分:解析器和事件处理器:

1)、解析器可以使用jaxp的API创建,创建出sax解析器后,就可以指定解析器去解析某个XML文档。

2)、解析器采用SAX方式在解析某个文档时,它只要解析到XML文档的一个组成部分都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的XML内容作为方法参数传递给事件处理器。

3)、 事件处理器是由程序员编写的,程序员通过事件处理器中方法的参数,就可以很轻松地得到SAX解析器解析到的数据,从而可以决定如何对数据进行处理。

2、简单的理解:获取工厂、解析器、xml文档的步骤是统一的,我们只需要实现一个事件处理器,而且自定义的事件处理器是要继承DefaultHandler即可,不然会要实现接口的很多方法。


3、通过SAX解析整个XML文档:

1)这边我们没有的事件处理器没有继承DefaultHandler,采用的是实现ContentHandler,会实现很多,非常麻烦,不推荐。

2)获取工厂、得到解析器、得到读取器、设置内容处理器、解析xml文档的步骤是固定的,主要在于自己写的事件处理器。

3)这边设置读取器、内容处理器、解析XML是分开执行的,也可以一步到位,解析器类SAXParser有这样的封装。

4)事件处理器中需要用到的是三个方法:

①、startElement():获取元素的开始便签和属性。

②、characters():获取元素的文本内容。

③、endElement():获取元素的结束标签。

代码如下:

/**
* 通过SAX解析整个XML
*/
private void getSaxXML() {
try {
// 1-: 获得SAX解析器工厂(工作的作用是用于创建具体的解析器)
SAXParserFactory spf = SAXParserFactory.newInstance();

// 2-:获得具体的SAX解析器
SAXParser tSAXParser = spf.newSAXParser();

// 3-:得到读取器
XMLReader xmlReader = tSAXParser.getXMLReader();

// 4-设置内容处理器
xmlReader.setContentHandler(new ListHandler());

// 5-: 解析一个xml文档
InputStream input = this.getClass().getClassLoader().getResourceAsStream("Request.xml");// 利用classloader加载xml文件
xmlReader.parse(new InputSource(input));

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

/**
*
* SaxJaxpXML.java
*
* @title 得到xml文档所有内容的Handler,继承自ContentHandler
* @description
* @author SAM-SHO
* @Date 2014-10-20
*/
class ListHandler implements ContentHandler {

private Logger logger = Logger.getLogger(ListHandler.class);

@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
// 开始标签
logger.debug("<" + qName + ">");

// 获取属性值
for (int i = 0; atts != null && i String attrName = atts.getQName(i);
String attrValue = atts.getValue(attrName);
logger.debug(attrName + "=" + attrValue + " ");

}

}

@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// xml文档内容
String cOntent= new String(ch, start, length);
logger.debug(content);

}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {

// 结束标签
logger.debug("");

}

@Override
public void endDocument() throws SAXException {
// TODO Auto-generated method stub

}

@Override
public void endPrefixMapping(String prefix) throws SAXException {
// TODO Auto-generated method stub

}

@Override
public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
// TODO Auto-generated method stub

}

@Override
public void processingInstruction(String target, String data) throws SAXException {
// TODO Auto-generated method stub

}

@Override
public void setDocumentLocator(Locator locator) {
// TODO Auto-generated method stub

}

@Override
public void skippedEntity(String name) throws SAXException {
// TODO Auto-generated method stub

}

@Override
public void startDocument() throws SAXException {
// TODO Auto-generated method stub

}

@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// TODO Auto-generated method stub

}

}


4、通过SAX获取指定标签的内容

1)我们利用SAXParser封装的方法,一步到位组装读取器、设置内容处理器、解析一个xml文档。

2)事件处理器直接继承DefaultHandler,然后重写需要的三个方法。

3)一个XML文件中相同名字的的元素可能会有多个,可以动态指定获取。

代码如下:

/**
* 获取指定标签
*/
private void getTagXML() {
try {
// 1-: 获得SAX解析器工厂(工作的作用是用于创建具体的解析器)
SAXParserFactory spf = SAXParserFactory.newInstance();

// 2-:获得具体的SAX解析器
SAXParser tSAXParser = spf.newSAXParser();

// 3-: 解析一个xml文档
InputStream input = this.getClass().getClassLoader().getResourceAsStream("Request.xml");// 利用classloader加载xml文件
tSAXParser.parse(new InputSource(input), new TagValueHandler());// 直接一步到位

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

/**
*
* SaxJaxpXML.java
*
* @title 获取指定标签的值,继承DefaultHandler
* @description
* @author SAM-SHO
* @Date 2014-10-20
*/
class TagValueHandler extends DefaultHandler {
private Logger logger = Logger.getLogger(TagValueHandler.class);

private String currentTag; // 记住当前解析到的是什么标签
private int needNumber = 2; // 记住想获取第几个作者便签的值,这边先定义为2
private int currentNumber = 0; // 当前解析到的是第几个

@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
currentTag = qName;
if (currentTag.equals("name")) {
currentNumber++;
}
}

@Override
public void characters(char[] ch, int start, int length) throws SAXException {
// 当前解析到的便签为第二个元素就输出
if ("name".equals(currentTag) && currentNumber == needNumber) {
String cOntent= new String(ch, start, length);
logger.debug(content);
}
}

@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
currentTag = null;// 置空

}

}





推荐阅读
  • 在本文中,我们将为 HelloWorld 项目添加视图组件,以确保控制器返回的视图路径能够正确映射到指定页面。这一步骤将为后续的测试和开发奠定基础。首先,我们将介绍如何配置视图解析器,以便 SpringMVC 能够识别并渲染相应的视图文件。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • Python 程序转换为 EXE 文件:详细解析 .py 脚本打包成独立可执行文件的方法与技巧
    在开发了几个简单的爬虫 Python 程序后,我决定将其封装成独立的可执行文件以便于分发和使用。为了实现这一目标,首先需要解决的是如何将 Python 脚本转换为 EXE 文件。在这个过程中,我选择了 Qt 作为 GUI 框架,因为之前对此并不熟悉,希望通过这个项目进一步学习和掌握 Qt 的基本用法。本文将详细介绍从 .py 脚本到 EXE 文件的整个过程,包括所需工具、具体步骤以及常见问题的解决方案。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • 在iOS开发中,基于HTTPS协议的安全网络请求实现至关重要。HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer)是一种旨在提供安全通信的HTTP扩展,通过SSL/TLS加密技术确保数据传输的安全性和隐私性。本文将详细介绍如何在iOS应用中实现安全的HTTPS网络请求,包括证书验证、SSL握手过程以及常见安全问题的解决方法。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • 在使用SSH框架进行项目开发时,经常会遇到一些常见的问题。例如,在Spring配置文件中配置AOP事务声明后,进行单元测试时可能会出现“No Hibernate Session bound to thread”的错误。本文将详细探讨这一问题的原因,并提供有效的解决方案,帮助开发者顺利解决此类问题。 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • HTML 页面中调用 JavaScript 函数生成随机数值并自动展示
    在HTML页面中,通过调用JavaScript函数生成随机数值,并将其自动展示在页面上。具体实现包括构建HTML页面结构,定义JavaScript函数以生成随机数,以及在页面加载时自动调用该函数并将结果呈现给用户。 ... [详细]
  • 深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案
    深入剖析Java中SimpleDateFormat在多线程环境下的潜在风险与解决方案 ... [详细]
  • Presto:高效即席查询引擎的深度解析与应用
    本文深入解析了Presto这一高效的即席查询引擎,详细探讨了其架构设计及其优缺点。Presto通过内存到内存的数据处理方式,显著提升了查询性能,相比传统的MapReduce查询,不仅减少了数据传输的延迟,还提高了查询的准确性和效率。然而,Presto在大规模数据处理和容错机制方面仍存在一定的局限性。本文还介绍了Presto在实际应用中的多种场景,展示了其在大数据分析领域的强大潜力。 ... [详细]
  • 七款高效编辑器与笔记工具推荐:KindEditor自动换行功能解析
    本文推荐了七款高效的编辑器与笔记工具,并详细解析了KindEditor的自动换行功能。其中,轻笔记QingBiJi是一款完全免费的记事本软件,用户可以通过其简洁的界面和强大的功能轻松记录和管理日常事务。此外,该软件还支持多平台同步,确保用户在不同设备间无缝切换。 ... [详细]
author-avatar
mobiledu2502913437
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有