IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> XML和JSON -> 正文阅读

[大数据]XML和JSON

前言

今日学习内容:XML和JSON


一、XML

1、简介

XML 可扩展标记语言(extensible Markup Language)

可扩展 -- > 标记可扩展

特性:

 1. xml具有平台无关性(无论哪种语言解析、无论哪类系统加载)
 2. xml具有自我描述性 (通俗易懂,类自我介绍)
 3. xml是一种标记语言,很类似 html(标记是一种特殊的语法)
 4. xml的设计宗旨是**传输数据**,而非显示数据
 5. xml**标签没有被预定义**,而html都是预定义标签
 6. xml是 W3C 的推荐标准

2、为什么学习xml

 1. 网络数据传输(更多用JSON)
*问题:一个登录请求 需要传送账号、密码 一串字符串
如何进行拆解??? 不一样的分割符号  不一样的分割标准 -->统一格式*
 2. 数据存储(使用较少)
 3. 配置文件(学习重点,学会编写)

3、扫盲

 -.XML文件是保存XML数据的一种方式 
 - xml json 本质上都是字符串
 -  XML数据也可以以其他的方式存在(如在内存中构建XML数据)  
 - 不要将XML语言狭隘的理解成XML文件

4、xml语法格式

  • XML文档声明
<?xml version="1.0" encoding="UTF-8"?>
  • 标记 ( 元素 / 标签 / 节点):XML文档由一个个的标记组成
  • 语法
开始标记(开放标记): <标记名称>
结束标记(闭合标记): </标记名称>
  • 标记名称: 自定义名称,必须遵循以下命名规则:
1.名称可以含字母、数字以及其他的字符
2.名称不能以数字或者标点符号开始
3.名称不能以字符 “xml”(或者 XML、Xml)开始
4.名称不能包含空格,不能包含冒号(:)
5.名称区分大小写
  • 标记内容: 开始标记与结束标记之间 ,是标记的内容.

5、语法重点

一个XML文档中, 必须有且且仅允许有一个根标记

正例:

<names>
<name>张三</name>
<name>李四</name>
</names>

反例:

<name>李四</name>
<name>麻子</name>

标记可以嵌套, 但是不允许交叉

正例:

<person>
<name>李四</name>
<age>18</age>
</person>

反例:

<person>
<name>李四<age></name>
18</age>
</person>

标记的层级称呼 (子标记, 父标记 , 兄弟标记, 后代标记 ,祖先标记)

例如:

<persons>
<person>
<name>李四</name>
<length>180cm</length>
</person>
<person>
<name>李四</name>
<length>200cm</length></person>
</persons>
name是person的子标记,也是person的后代标记  
name是persons的后代标记 
name是length的兄弟标记 
person是name的父标记 
persons是name的祖先标记

标记名称 允许重复

标记除了开始和结束 , 还有属性

标记中的属性, 在标记开始时 描述, 由属性名和属性值 组成.
·格式:
在开始标记中, 描述属性.
可以包含0-n个属性, 每一个属性是一个键值对!
属性名不允许重复 , 键与值之间使用等号连接, 多个属性之间使用空格、换行分割.
属性值 必须被引号引住.

案例:

<persons>
<person id="10001" groupid="1">
<name>李四</name>
<age>18</age>
</person>
<person id="10002" groupid="1">
<name>李四</name>
<age>20</age>
</person>
</persons>

注释

注释不能写在文档文档声明前
注释不能嵌套注释
·格式:
注释开始: <!--
注释结束: -->
可以用记事本的格式创建文档进行编写练习

案例:

<?xml version = "1.0" encoding = "UTF-8"?>
<books>
<book id = "1001">
<id>1001</id>  
<!--两种书写方式,可以作为属性写在标记后面,也可以单独作为一个标记 -->
<name>金苹果</name>
<info>描述了金苹果的种植过程</info>
</book>
<book id = "1002">
<name>银苹果</name>
<info>描述了银苹果的种植过程</info>
</book>
</books>

二、xml解析

1、SAX解析

优点:

 1. 分析能够立即开始,而不是等待所有的数据被处理
 2. 逐行加载,节省内存 有助于解析大于系统内存的文档
 3. 有时不必解析整个文档,它可以在某个条件的到满足时停止解析
缺点:
 1. 单向解析,无法定位文档层次,无法同时访问同一文档的不同部分数据(因为逐行解析,当解析第N行时,第N-1行已经被释放了,无法再进行操作)
 2. 无法得知事件发生时元素的层次,只能自己维护节点的父/子关系
 3. 只读解析方式,无法修改xml文档的内容

2、DOM解析

是用与平台和语言无关的方式表示xml文档的官方w3c标准,分析该结构通常需要加载整个文档和内存中建立文档树模型。程序员可以通过操作文档树,来完成数据的获取、修改、删除等

优点:

 1. 文档在内存中加载,允许对数据和结构做出更改
 2. 访问是双向的,可以在任何时候在树中双向解析数据

缺点:
 文档全部加载在内存中,消耗资源大

3、JDOM解析

  目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一 个Java特定模型,JDOM一直得到大力推广和促进。 
  JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题” (根据学习曲线假定为20%)
  
优点:

 1. 使用具体类而不是接口,简化了DOM的API
 2. 大量使用了Java集合类,方便了Java开发人员

缺点:
 1. 没有较好的灵活性
 2. 性能不是那么优异
 

4、DOM4J解析

它是JDOM的一种智能分支。合并了许多超出基本XML文档表示的功能,
包括集成的XPath 支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。
它还提供了构建文档表示的选项, DOM4J是一个非常优秀的Java XML API,
具有性能优异、功能强大和极端易用使用的特点;
同时它也是一 个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML。 
目前许多开源项目中大量采用DOM4J , 例如:Hibernate

三、SAX解析实例

1、解析本地文件

Demo1.xml

<?xml version="1.0" encoding="UTF-8"?>
<books>
    <book id = "1001">
        <name>金苹果</name>
        <info>锄禾日当午</info>
    </book>
    <book id = "1002">
        <name>银苹果</name>
        <info>汗滴禾下土</info>
    </book>
    <book id = "1003">
        <name>红苹果</name>
        <info>谁知盘中餐</info>
    </book>
    <book id = "1004">
        <name>青苹果</name>
        <info>粒粒皆辛苦</info>
    </book>
</books>

Demo1.java

package demoXML;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

public class Demo1 {
    /*
    * 解析本地文件
    * */
    public static void main(String[] args) throws IOException, DocumentException {
        //1. 获取指向xml文件的输入流(注意文件一定要是xml结尾的)
        FileInputStream fis = new FileInputStream("B://Demo1.xml");
        //2.创建XML读取对象(用SAX读取)
        SAXReader sr = new SAXReader();
        //3.读取并得到文档对象
        Document doc = sr.read(fis);
        //4.通过文档获取根元素
        Element root = doc.getRootElement();
        //5.开始解析元素
        System.out.println(root.getName());
        
        //6.从根节点root开始层层搜索
        Element book = root.element("book");
        Element name = book.element("name");
        Element info = book.element("info");
        System.out.println(name.getText());
        System.out.println(info.getText());

       //7.遍历子节点内容
        List<Element> es = root.elements();
        for (int i = 0; i < es.size(); i++) {
            Element book_i = es.get(i);
            //1.获取booK 中的id属性值
            System.out.println(book_i.attributeValue("id"));
            //2.获取book 中子节点name的文本值
            System.out.println(book_i.elementText("name"));
            //3.获取book 中子节点info的文本值
            System.out.println(book_i.elementText("info"));
            System.out.println("--------------");
        }
        //8.关闭资源
        fis.close();
    }
}

Element类提供的方法

MethodComment
getQName()元素的QName对象
getNamespace()元素所属的Namespace对象
getNamespacePrefix()元素所属的Namespace对象的prefix
getNamespaceURI()元素所属的Namespace对象的URL
getName()元素的Local name
getQualifiedName()元素的qualified name
getText()元素所含有的text内容,如果内容为空则返回一个空字符串而不是Null
getTextTrim()元素所含有的text内容,其中连续的空格被转化为单个空格,该方法不会返回null
attributeIterator()元素属性的iterator,其中每个元素都是Attribute对象
attributeValue()元素的某个指定属性所含的值
elementIterator()元素的子元素的iterator,其中每个元素都是Element对象
element()元素的某个指定(qualified name或者local name)的子元素
elementText()元素的某个指定(qualified name或者local name)的子元素中的text信息
getParent元素的父元素
getPath()元素的XPath表达式,其中父元素的qualified name和子元素的qualified name之间使用"/"分隔
isTextOnly()是否该元素只含有text或是空元素
isRootElement()是否该元素是XML树的根节点

2、解析网络文件

地址:[https://apis.juhe.cn/mobile/get?%20phone=15363397414&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253]

Demo2.java

package demoXML;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class Demo2 {
    public static void main(String[] args) throws IOException, DocumentException {
        String phone = "18826584526";
        //1.获取到XML资源的输入流
        //(1) 新建一个地址对象
        URL url = new URL("http://apis.juhe.cn/mobile/get? phone="+ phone +"&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
        //(2) 打开与地址的连接
        URLConnection conn = url.openConnection();
        //(3) 通过连接conn获取输入流
        InputStream is = conn.getInputStream();
        //2.创建一个xml读取对象
        SAXReader sr = new SAXReader();
        //3.通过读取对象 读取xml数据 并返回文档对象
        Document doc = sr.read(is);
        //4.获取根节点
        Element root = doc.getRootElement();
        //5.解析内容

        //获取根节点root下的子节点resultcode的值
        String code = root.elementText("resultcode");
        if(code.equals("200")){
            Element result = root.element("result");
            String province = result.elementText("province");
            String city = result.elementText("city");
            if(province.equals(city)){
                System.out.println("手机号归属地为:" + city);
            }else {
                System.out.println("手机号" + phone + "的归属地为:" + province + "省" + city + "市");
            }
        }else {
            System.out.println("请输入正确的手机号码/网址");
        }
        //6.关闭资源
        is.close();
    }
}

四、XPATH解析

1、通过路径快速查找一个或一组元素

2、路径表达式

1. / : 从根节点开始查找 
2. // : 从发起查找的节点位置 查找后代节点 *** 
3. . : 查找当前节点 
4. .. : 查找父节点 
5. @ : 选择属性. 
   属性使用方式: 
		[@属性名='值'] [@属性名>'值'] [@属性名<'值'] [@属性名!='值']
books: 路径: //book[@id='1']//name 
	books
		book id=1 
			name 
			info 
		book id=2 
			name 
			info

3、使用步骤

通过Node类的两个方法, 来完成查找:
 (Node是 Document 与 Element 的父接口) 
 方法1.
 	//根据路径表达式, 查找匹配的单个节点 
 	Element e = selectSingleNode("路径表达式"); 
 方法2.
 	List<Element> es = selectNodes("路径表达式");

4、案例

Demo3.java – 解析本地文件(Demo1.xml)

package demoXML;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

public class Demo3 {
    /*
    * Xpath解析Demo1.xml
    * */
    public static void main(String[] args) throws IOException, DocumentException {
        //1. 获取指向xml文件的输入流
        FileInputStream fis = new FileInputStream("B://Demo1.xml");
        //2.创建XML读取对象
        SAXReader sr = new SAXReader();
        //3.读取并得到文档对象
        Document doc = sr.read(fis);
        //4.通过文档对象+xpath 查找所有的name节点
        List<Node> names = doc.selectNodes("//name");
        for (int i = 0; i < names.size(); i++) {
            //获取子节点的标记名
            System.out.println(names.get(i).getName());
            //获取该子节点下的值
            System.out.println(names.get(i).getText());
        }
        //5.精准路径 -- > 只查询id为1001的name
        List<Node> name_1 = doc.selectNodes("//book[@id = '1001']//name");
        System.out.println(name_1.get(0).getText());
        //6.当只有一条记录,可以采用下面这种方法
        Node node = doc.selectSingleNode("//book[@id = '1001']//name");
        System.out.println(node.getName() + ":" + node.getText());
        //7.关闭资源
        fis.close();
    }
}

Demo4.java – 解析网络文件

package demoXML;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;

public class Demo3 {
    /*
    * Xpath解析Demo1.xml
    * */
    public static void main(String[] args) throws IOException, DocumentException {
        //1. 获取指向xml文件的输入流
        FileInputStream fis = new FileInputStream("B://Demo1.xml");
        //2.创建XML读取对象
        SAXReader sr = new SAXReader();
        //3.读取并得到文档对象
        Document doc = sr.read(fis);
        //4.通过文档对象+xpath 查找所有的name节点
        List<Node> names = doc.selectNodes("//name");
        for (int i = 0; i < names.size(); i++) {
            //获取子节点的标记名
            System.out.println(names.get(i).getName());
            //获取该子节点下的值
            System.out.println(names.get(i).getText());
        }
        //5.精准路径 -- > 只查询id为1001的name节点
        List<Node> name_1 = doc.selectNodes("//book[@id = '1001']//name");
        System.out.println(name_1.get(0).getText());
        //6.当只有一条记录,可以采用下面这种方法
        Node node = doc.selectSingleNode("//book[@id = '1001']//name");
        System.out.println(node.getName() + ":" + node.getText());
        //7.关闭资源
        fis.close();
    }
}

五、生成XML

1、Java生成xml文件

(1)步骤

1. 通过文档帮助器 (DocumentHelper) , 创建空的文档对象
	Document doc = DocumentHelper.createDocument(); 
2. 通过文档对象, 向其中添加根节点 
	Element root = doc.addElement("根节点名称"); 
3. 通过根节点对象root , 丰富我们的子节点 
	Element e = root.addElement("元素名称"); 
4. 创建一个文件输出流 ,用于存储XML文件 
	FileOutputStream fos = new FileOutputStream("要存储的位置"); 
5. 将文件输出流, 转换为XML文档输出流 
	XMLWriter xw = new XMLWriter(fos); 
6. 写出文档
	xw.write(doc); 
7. 释放资源
	xw.close();

(2)实例

package demoXML;

import jdk.internal.util.xml.XMLStreamException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;

import java.io.FileOutputStream;
import java.io.IOException;

public class Demo5 {
    public static void main(String[] args) throws XMLStreamException, IOException {
        //1. 通过文档帮助器 (DocumentHelper) , 创建一个空的文档对象
        Document doc = DocumentHelper.createDocument();
        //2. 通过文档对象, 向其中添加根节点(第一个节点)
        Element root = doc.addElement("students");
        //3. 通过根节点对象root , 丰富子节点
        for (int i = 0; i < 5; i++) {
            Element student = root.addElement("student");
            Element name = student.addElement("name");
            name.setText("李" + i);
            Element age = student.addElement("age");
            age.setText(" " + (i + 1)*2);
            student.addAttribute("id",1000 + i + "");
        }
        //4. 创建一个文件输出流 ,用于存储XML文件
        FileOutputStream fos = new FileOutputStream("B://students.xml");
        //5. 将文件输出流, 转换为XML文档输出流
        XMLWriter xw = new XMLWriter(fos);
        //6. 写出文档
        xw.write(doc);
        //7. 释放资源
        xw.close();
        System.out.println("执行完毕!");
    }

}

生成结果 students.xml

<?xml version="1.0" encoding="UTF-8"?>
<students>
    <student id="1000">
        <name>李0</name>
        <age>2</age>
    </student>
    <student id="1001">
        <name>李1</name>
        <age>4</age>
    </student>
    <student id="1002">
        <name>李2</name>
        <age>6</age>
    </student>
    <student id="1003">
        <name>李3</name>
        <age>8</age>
    </student>
    <student id="1004">
        <name>李4</name>
        <age>10</age>
    </student>
</students>

2、XStream生成xml文件

package demoXML;

import com.thoughtworks.xstream.XStream;
/*
* 使用XStream生成Xml文件
* */
public class Demo6 {
    public static void main(String[] args) {
        Person p = new Person();
        p.setName( "易拉罐" );
        p.setAge( 22 );

        //XStream的使用 -- > 生成XML文件
        //1.创建XStream对象
        XStream x = new XStream();
        //2.修改生成的根节点(可选,默认为“包名.类名”
        x.alias( "person",Person.class);
        //3.传入对象p   开始生成xml
        String xml = x.toXML(p);
        //4.输出xml文件格式的p对象
        System.out.println(xml);
    }

    static  class Person{
        private String name;
        private int age;

        public Person() {
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

六、JSON

1、简介

JavaScript Object Notation JS对象简谱 , 是一种轻量级数据交换格式

2、对象格式

java
   class Book{
   		private String name;
   		private String info;
   		get/set...
   	}
Book b = new Book();
b.setName("");
b.setInfo("");

js:
	var b = new Object();
	b.name = "";
	b.info = "";

XML:
	<book>
		<name> </name>
		<info> </info>
	</book>

JSON:
	{
		"name" : "",
		"info" : ""
	}

3、数组格式

在JSON格式中可以与对象互相嵌套
[元素1,元素2...]
数组钟可以包含多种数据类型

4、案例

一个对象, 由一个大括号表示. 
	括号中 描述对象的属性 . 通过键值对来描述对象的属性
	(可以理解为, 大括号中, 包含的是一个个的键值对.)  
	格式:
		1.键与值之间使用冒号连接, 多个键值对之间使用逗号分隔. 
		2.键值对的键 应使用引号引住 (通常Java解析时, 键不使用引号会报错. 而JS能正确解 析.) 
		3.键值对的值, 可以是JS中的任意类型的数据
{
            "name":"伟杰老师",
                "age":18,
                "pengyou":["张三", "李四", "王二", "麻子", {
                "name":"野马老师",
                "info":"像匹野马一样狂奔在技术钻研的道路上"
            }],
            "heihei":{ "name":"大长刀",
                "length":"40m"
            }
        }

5、缺点

无限嵌套 难以理解

6、解析JSON文件

Book.class

package demoJSON;

public class Book {
    private String id;
    private String name;
    private String info;

    public Book() {
    }

    public Book(String id, String name, String info) {
        this.id = id;
        this.name = name;
        this.info = info;
    }

    @Override
    public String toString() {
        return "Book{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", info='" + info + '\'' +
                '}';
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}

1、谷歌 Gson
/*
    * 使用谷歌Gson  对象 --> JSON格式的对象
    * */

    public static void main(String[] args) {
        //1. 创建Gson对象
        Gson gson = new Gson();
        //2. 转换
        Book book = new Book("100", "金苹果", "种植苹果真幸苦!");
        String s = gson.toJson( book );
        System.out.println(s);


        //使用匿名对象
        Book book1 = new Book("100", "金苹果", "种植苹果真幸苦!");
        String s1 = new Gson().toJson( book );
        System.out.println(s1);
    }
/*
    * 使用谷歌Gson  JSON格式的对象 --> Book.class类型对象
    * */
    public static void main(String[] args) {
        //1.创建Gson对象
        Gson gson = new Gson();
        //2.转换  {"id":"100","name":"金苹果","info":"种植苹果真幸苦!"}
        Book book = gson.fromJson( "{\"id\":\"100\",\"name\":\"金苹果\",\"info\":\"种植苹果真幸苦!\"}",Book.class);
        System.out.println(book.getId());
    }
/*
    * 使用谷歌Gson  JSON格式的对象(嵌套数组) --> HashMap.class类型对象
    * */
    public static void main(String[] args) {
        //1.创建Gson对象
        Gson gson = new Gson();
        //2.转换  {"id":"100","name":"金苹果","info":"种植苹果真幸苦!","page":["嘻嘻","哈哈","嘿嘿"]}
        HashMap data = gson.fromJson( "{\"id\":\"100\",\"name\":\"金苹果\",\"info\":\"种植苹果真幸苦!\",\"page\":[\"嘻嘻\",\"哈哈\",\"嘿嘿\"]}", HashMap.class );
        //3.当解析的内容包含数组(page)时,解析后会生成list对象的数据
        List page = (List) data.get("page");
        System.out.println(page.get(2));
    }
2、阿里云 FastJson
/*
    * 使用阿里云FastJson  对象 --> JSON格式的对象
    * */
    public static void main(String[] args) {
        //1. 创建一个Book对象
        Book book = new Book("1002","吃饭歌","吃饭?喝粥?嗦粉?吃面?啃堡?" );
        //2. toJSONString()方法
        String json = JSON.toJSONString( book );
        System.out.println(json);
    }
/*
    * 使用阿里云FastJson  JSON格式的对象 --> Book.class类型对象
    * */
    public static void main(String[] args) {
        //1.转对象 {"id":"1002","info":"吃饭?喝粥?嗦粉?吃面?啃堡?","name":"吃饭歌"}
        Book book = JSON.parseObject( "{\"id\":\"1002\",\"info\":\"吃饭?喝粥?嗦粉?吃面?啃堡?\",\"name\":\"吃饭歌\"}", Book.class );
        System.out.println(book.getId());
    }
/*
    * 使用阿里云FastJson  JSON格式的数组 --> String.class类型对象
    * */
    public static void main(String[] args) {
        //2.转数组 ["螺蛳粉","酸菜鱼","牛肉面"]  parseArray()
        List<String> string = JSON.parseArray( "[\"螺蛳粉\",\"酸菜鱼\",\"牛肉面\"]", String.class );
        System.out.println(string.get(1));
    }

总结

JSON 在给用户发送信息给对象 这一点很重要 !!!

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:21:27  更:2021-09-29 10:22:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 1:29:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码