当前位置: 首页 > news >正文

Springboot+Vue3 整合海康获取视频流并展示

目录

1.后端

1.1 导入依赖

1.2 代码实战

2.前端

2.1 首先安装海康的web插件,前端vue3代码如下:


1.后端

1.1 导入依赖

        <dependency><groupId>com.hikvision.ga</groupId><artifactId>artemis-http-client</artifactId><version>1.1.3</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.51</version></dependency>

1.2 代码实战

新建ArtemisPostTest类,代码如下,设置认证信息,设置ArtemisConfig的host,appKey(AK),appSecret(SK)。设置接口URL。.设置接口入参。接口调用,调用doPostStringArtemis方法(该方法内部实现了登入认证逻辑),传入接口URL,接口入参,数据提交类型等信息,完成接口调用。

public class ArtemisPostTest {static {ArtemisConfig.host = "";// 代理API网关nginx服务器ip端口ArtemisConfig.appKey = "";// 秘钥appkeyArtemisConfig.appSecret = "";// 秘钥appSecret}/*** 能力开放平台的网站路径* TODO 路径不用修改,就是/artemis*/private static final String ARTEMIS_PATH = "/artemis";public static String path="";public static JSONObject jsonBody=new JSONObject();/*** 调用POST请求类型(application/json)接口,这里以入侵报警事件日志为例* https://open.hikvision.com/docs/918519baf9904844a2b608e558b21bb6#e6798840** @return*/public static String callPostStringApi(){/*** http://10.33.47.50/artemis/api/scpms/v1/eventLogs/searches* 根据API文档可以看出来,这是一个POST请求的Rest接口,而且传入的参数值为一个json* ArtemisHttpUtil工具类提供了doPostStringArtemis这个函数,一共六个参数在文档里写明其中的意思,因为接口是https,* 所以第一个参数path是一个hashmap类型,请put一个key-value,query为传入的参数,body为传入的json数据* 传入的contentType为application/json,accept不指定为null* header没有额外参数可不传,指定为null**/final String getCamsApi = ARTEMIS_PATH +ArtemisPostTest.path;Map<String, String> path = new HashMap<String, String>(2) {{put("https://", getCamsApi);//根据现场环境部署确认是http还是https}};String body = jsonBody.toJSONString();String result = ArtemisHttpUtil.doPostStringArtemis(path,body,null,null,"application/json",null);// post请求application/json类型参数return result;}}

新建实体类Camera代码如下:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class Camera {String cameraIndexCode;String camereName;String url;
}

在Controller中进行调用,代码如下:

首先根据分页获取监控点列表,这里获取的是第三页,每一页为六个监控点。

查询监控点列表v2

接口说明

根据条件查询目录下有权限的监控点列表

接口版本

v2

接口地址

/api/resource/v2/camera/search

请求方法

POST

数据提交方式

application/json

 然后根据监控点唯一的标识获取预览url

接口说明

1.平台正常运行;平台已经添加过设备和监控点信息。
2.平台需要安装mgc取流服务。
3.三方平台通过openAPI获取到监控点数据,依据自身业务开发监控点导航界面。
4.调用本接口获取预览取流URL,协议类型包括:hik、rtsp、rtmp、hls。
5.通过开放平台的开发包进行实时预览或者使用标准的GUI播放工具进行实时预览。
6.为保证数据的安全性,取流URL设有有效时间,有效时间为5分钟。

接口版本

v2

接口地址

/api/video/v2/cameras/previewURLs

请求方法

POST

数据提交方式

application/json

最后就是进行属性的赋值,赋值给建立的Camera 实体类。

    @GetMapping("/test")public List<Camera> test(){ArtemisPostTest.path="/api/resource/v1/cameras";ArtemisPostTest.jsonBody.clear();ArtemisPostTest.jsonBody.put("pageNo", 3);ArtemisPostTest.jsonBody.put("pageSize", 6);String StringeResult = ArtemisPostTest.callPostStringApi();JSONObject result = (JSONObject) JSONObject.parse(StringeResult);String data = result.get("data").toString();JSONObject resultdata = (JSONObject) JSONObject.parse(data);JSONArray list = resultdata.getJSONArray("list");
//        System.out.println("StringeResult结果示例: "+JSONObject.toJSON(StringeResult));
//		callPostImgStringApi();ArtemisPostTest.path="/api/video/v2/cameras/previewURLs";List<Camera> cameraList=new ArrayList<>();for (Object i : list) {Camera camera=new Camera();JSONObject jsonObject = (JSONObject) JSONObject.parse(i.toString());String cameraIndexCode = jsonObject.get("cameraIndexCode").toString();String cameraName = jsonObject.get("cameraName").toString();ArtemisPostTest.jsonBody.clear();ArtemisPostTest.jsonBody.put("cameraIndexCode",cameraIndexCode);ArtemisPostTest.jsonBody.put("protocol","rtsp");String m = ArtemisPostTest.callPostStringApi();JSONObject jsonObject1 = (JSONObject) JSONObject.parse(m);JSONObject data1 = (JSONObject) jsonObject1.get("data");String url = data1.get("url").toString();camera.setCameraIndexCode(cameraIndexCode).setCamereName(cameraName).setUrl(url);cameraList.add(camera);}return cameraList;}

2.前端

2.1 首先安装海康的web插件,前端vue3代码如下:

<template><div style="display: flex;flex-direction: row;flex-wrap: wrap"><div v-for="item in state.list"><el-button @click="go(item.cameraIndexCode)">预览{{item.camereName}}</el-button></div></div><div class="main" ref="playWndBox"><divid="playWnd"class="playWnd":style="{height: playWndHeight + 'px',width: playWndWidth + 'px',}"></div></div>
</template><script setup>import { ref, onMounted, onBeforeUnmount, getCurrentInstance, nextTick,reactive } from 'vue'import axios from "../utils/axios.js"const playWndBox = ref(null)let playWndHeight = ref('')let playWndWidth = ref('')let pubKey = ref('')let oWebControl = ref(null)let objData = ref({appkey: "",                 //海康提供的appkeyip: "",                     //海康提供的ipsecret: "",                 //海康提供的secretport: 443,playMode: 0,        // 0 预览 1回放layout: "1x1",      //页面展示的模块数【16】})const go=(data)=>{previewVideo(data)}const state=reactive({list:[]})const load=()=>{axios.get("/test").then(res=>{state.list=resconsole.log(res)})}load()onMounted(() => {// 获取页面的实例对象const pageInstance = getCurrentInstance();// 获取dom节点对象const tagDomObj = pageInstance.refs.playWndBox;playWndHeight.value = tagDomObj.clientHeight;playWndWidth.value = tagDomObj.clientWidth;// 监听scroll事件,使插件窗口尺寸跟随DIV窗口变化window.addEventListener("scroll", () => {console.log(5);// returnif (oWebControl.value != null) {oWebControl.JS_Resize(tagDomObj.clientWidth,tagDomObj.clientHeight);this.setWndCover();}});// 监听resize事件,使插件窗口尺寸跟随DIV窗口变化window.addEventListener("resize", (e) => {console.log(0);if (oWebControl.value != null) {oWebControl.JS_Resize(tagDomObj.clientWidth,tagDomObj.clientHeight);this.setWndCover();}});// 初始化播放器插件nextTick(() => {initPlugin();})})onBeforeUnmount(() => {if (oWebControl.value != null) {// 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题oWebControl.JS_HideWnd();// 销毁当前播放的视频oWebControl.JS_RequestInterface({ funcName: "destroyWnd" });// 断开与插件服务连接oWebControl.JS_Disconnect();}})const initPlugin = () => {oWebControl = new WebControl({szPluginContainer: "playWnd", // 指定容器idiServicePortStart: 15900, // 指定起止端口号,建议使用该值iServicePortEnd: 15900,szClassId: "23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsidcbConnectSuccess: () => {// 创建WebControl实例成功oWebControl.JS_StartService("window", {// WebControl实例创建成功后需要启动服务// 值"./VideoPluginConnect.dll"写死dllPath: "./VideoPluginConnect.dll",}).then(function () {// 设置消息回调oWebControl.JS_SetWindowControlCallback({// cbIntegrationCallBack: cbIntegrationCallBack,});//JS_CreateWnd创建视频播放窗口,宽高可设定oWebControl.JS_CreateWnd("playWnd", 1152, 581, { bEmbed: true })//这一部分很重要,两个参数为你盒子的宽高,这样是写死是防止组件加载之前出现白屏;bEmbed: true 防止窗口闪烁.then(function () {// 创建播放实例成功后初始化init();});},function () {// 启动插件服务失败});},// 创建WebControl实例失败cbConnectError: function () {// 这里写创建WebControl实例失败时的处理步骤,下面的代码仅做参看,具体实现步骤根据个人需求进行编写!!!!!!!!// console.log(0);// oWebControl.value = null;// // 程序未启动时执行error函数,采用wakeup来启动程序// window.WebControl.JS_WakeUp("VideoWebPlugin://");// initCount++;// if (initCount < 3) {//   setTimeout(function () {//     initPlugin();//   }, 3000);// } else {//   setTimeout(function () {//     setTimeout(function () {//       $router.push('/home/PlugDown')//     }, 4000)//   }, 4000)// }},cbConnectClose: () => {// 异常断开:bNormalClose = false// JS_Disconnect正常断开:bNormalClose = true// console.log("cbConnectClose");oWebControl.value = null;},});// oWebControl.JS_CuttingPartWindow(500, 500, 500, 500);}// 初始化const init = (callback) => {getPubKey(() => {let appkey = objData.value.appkey;                   //综合安防管理平台提供的appkey,必填let secret = setEncrypt(objData.value.secret); //综合安防管理平台提供的secret,必填let ip = objData.value.ip;                           //综合安防管理平台IP地址,必填let playMode = objData.value.playMode;                //初始播放模式:0-预览,1-回放let port = objData.value.port;                        //综合安防管理平台端口,若启用HTTPS协议,默认443let snapDir = "D:\\SnapDir";                        //抓图存储路径let videoDir = "D:\\VideoDir";                      //紧急录像或录像剪辑存储路径let layout = objData.value.layout;                   //playMode指定模式的布局let enableHTTPS = 1;                                //是否启用HTTPS协议与综合安防管理平台交互,这里总是填1let encryptedFields = "secret";                     //加密字段,默认加密领域为secretlet showToolbar = 1;                                //是否显示工具栏,0-不显示,非0-显示let showSmart = 0;                                  //是否显示移动框线框,0-不显示,非0-显示let buttonIDs ="0,16,256,257,258,259,260,512,513,514,515,516,517,768,769"; //自定义工具条按钮// var toolBarButtonIDs = "2049,2304" // 工具栏上自定义按钮oWebControl.JS_RequestInterface({funcName: "init",argument: JSON.stringify({appkey: appkey,         //API网关提供的appkeysecret: secret,         //API网关提供的secretip: ip,                 //API网关IP地址playMode: playMode,      //播放模式(决定显示预览还是回放界面)port: port,             //端口snapDir: snapDir,       //抓图存储路径videoDir: videoDir,     //紧急录像或录像剪辑存储路径layout: layout,         //布局enableHTTPS: enableHTTPS,   //是否启用HTTPS协议encryptedFields: encryptedFields, //加密字段showToolbar: showToolbar, //是否显示工具栏showSmart: showSmart,   //是否显示智能信息buttonIDs,              //自定义工具条按钮}),}).then(function (oData) {oWebControl.JS_Resize(playWndWidth.value, playWndHeight.value); // 初始化后resize一次,规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题if (callback) {callback();}// 隐藏// oWebControl.JS_HideWnd()});});}// RSA 加密let setEncrypt = (value) => {let encrypt = new window.JSEncrypt();encrypt.setPublicKey(pubKey);return encrypt.encrypt(value);}// 获取公钥const getPubKey = (callback) => {oWebControl.JS_RequestInterface({funcName: "getRSAPubKey",argument: JSON.stringify({keyLength: 1024,}),}).then(function (oData) {if (oData.responseMsg.data) {pubKey = oData.responseMsg.data;callback();}});}// 调用这个函数可进行视频播放// 视频预览功能const previewVideo = (data) => {let cameraIndexCode = data;  // 获取输入的监控点编号值,必填let streamMode = 0;          // 主子码流标识:0-主码流,1-子码流let transMode = 1;           // 传输协议:0-UDP,1-TCPlet gpuMode = 0;             // 是否启用GPU硬解,0-不启用,1-启用let wndId = -1;              // 播放窗口序号(在2x2以上布局下可指定播放窗口)oWebControl.JS_RequestInterface({funcName: "startPreview",argument: JSON.stringify({cameraIndexCode: cameraIndexCode, // 监控点编号streamMode: streamMode,                 // 主子码流标识transMode: transMode,                   // 传输协议gpuMode: gpuMode,                       // 是否开启GPU硬解wndId: wndId,                           // 可指定播放窗口}),}).then(function () {oWebControl.JS_SetWindowControlCallback({});});}</script><style scoped>.main {position: fixed;top: 50%;left: 20%;transform: translateY(-50%);width: 60vw;height: 60vh;margin: auto;background-color: #ccc;}
</style>

相关文章:

Springboot+Vue3 整合海康获取视频流并展示

目录 1.后端 1.1 导入依赖 1.2 代码实战 2.前端 2.1 首先安装海康的web插件&#xff0c;前端vue3代码如下&#xff1a; 1.后端 1.1 导入依赖 <dependency><groupId>com.hikvision.ga</groupId><artifactId>artemis-http-client</artifactId&g…...

Linux——进程退出

目录 一.进程退出时有三种选择&#xff1a; 1.1 echo $?命令&#xff1a; 功能&#xff1a; 打印距离现在最近一次执行某进程的退出码 例2代码&#xff1a; 例3&#xff1a; 例4代码&#xff1a; 1.3 进程运行过程中可能会出现的错误种类&#xff1a; 二.总结&#xff…...

组长给组员派活,把组长自己的需求和要改的bug派给组员,合理吗?

组长把自己的工作派给手下&#xff0c;合理吗&#xff1f; 一位程序员问&#xff1a; 组长给他派活&#xff0c;把组长自己的需求或者要改的bug派给他。组长分派完需求之后&#xff0c;他一个人干两个项目&#xff0c;组长却无所事事&#xff0c;这样合理吗&#xff1f; 有人说…...

Spring注解开发——bean的作用范围与生命周期管理

文章目录 1.bean管理1.1 bean作用范围Scope注解 1.2 bean生命周期PostConstructPreDestroy 2.小结 1.bean管理 1.1 bean作用范围 Scope注解 不写或者添加Scope(“singleton”)表示的是单例 如何配置多例&#xff1f; 在Scope(“prototype”)表示的是多例 1.2 bean生命周…...

C++ > Cmake

目录 编译器 多文件编译与链接 Makefile构建系统 编译器 厂商 C C GNU gcc g main.cpp #include <cstdio>int main() {printf("Hello, world!\n");return 0; }编译器, 是一个根据源代码生成机器码的程序 g main.cpp -o a.out调用编译器程序g, 读…...

Spring的Bean的生命周期

Spring的Bean的生命周期 Spring的Bean的生命周期 Spring的Bean的生命周期 Spring的Bean的生命周期包括以下阶段&#xff1a; &#xff08;1&#xff09;实例化Instantiation&#xff08;2&#xff09;填充属性Populate properties&#xff08;3&#xff09;处理Aware接口的回调…...

在树莓派上搭建WordPress博客网站,并内网穿透发布到公网

✨个人主页&#xff1a;bit me&#x1f447; 目 录 &#x1f43e;概述&#x1f490;安装 PHP&#x1f338;安装MySQL数据库&#x1f337;安装 Wordpress&#x1f340;设置您的 WordPress 数据库&#x1f339;设置 MySQL/MariaDB&#x1f33b;创建 WordPress 数据库 &#x1f33…...

跨平台C++ Qt数据库管理系统设计与实战:从理论到实践的全面解析

跨平台C Qt数据库管理系统设计与实战&#xff1a;从理论到实践的全面解析 一、引言&#xff08;Introduction&#xff09;1.1 数据库管理系统的重要性&#xff08;Importance of Database Management Systems&#xff09;1.2 C和Qt在数据库管理系统中的应用&#xff08;Applica…...

Ubuntu crontab定时任务

1. crontab 相关的命令&#xff1a; 安装&#xff1a;apt-get install cron 启动&#xff1a;service cron start 重启&#xff1a;service cron restart 停止&#xff1a;service cron stop 检查状态&#xff1a;service cron status 查询cron可用的命令&#xff1a;service …...

ChatGPT Prompt Engineering for Developers 大语言模型引导词指导手册

以下内容均整理来自deeplearning.ai的同名课程 Location 课程访问地址 https://learn.deeplearning.ai/chatgpt-prompt-eng 一、Guidelines for Prompting 引导语的编写原则 Prompting Principles 引导语编写原则 Principle 1: Write clear and specific instructions编写清晰…...

【Vue】二:Vue核心处理---模板语法

文章目录 1.模板语法---插值2.模板语法---指令语法2.1v-once2.2 v-bind2.3 v-model2.4 v-on 3.MVVM4.事件回调函数中的this 1.模板语法—插值 {{可以写什么}} &#xff08;1&#xff09;在data中声明的变量&#xff0c;函数 &#xff08;2&#xff09;常量 &#xff08;3&…...

windows环境下nginx+ftp服务器搭建简易文件服务器

这里写目录标题 1&#xff0c;前言2&#xff0c;FTP服务器搭建3&#xff0c;nginx安装 1&#xff0c;前言 几种文件服务器的对比 1&#xff0c;直接使用ftp服务器&#xff0c;访问图片路径为 ftp://账户:密码192.168.0.106/31275-105.jpg不采用这种方式&#xff0c;不安全容易…...

【数据结构与算法】图的概述(内含源码)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️数据结构与算法】 学习名言&#xff1a;天子重英豪&#xff0c;文章教儿曹。万般皆下品&#xff0c;惟有读书高——《神童诗劝学》 系列文章目录 第一章 ❤️ 学前知识 第二章 ❤️ 单向链表 第三章…...

SAP MM 根据采购订单反查采购申请

如何通过采购订单号查询到其前端的采购申请号。 首先从采购申请的相关报表着手&#xff0c;比如ME5A, 发现它是可以满足需求的。 例如&#xff1a;如下的采购订单&#xff0c; 该订单是由采购申请10003364转过来的。 如果想通过这个采购订单找到对应的采购申请&#xff0c;在…...

C语言程序设计题/C语言计算机二级考前押题版

C语言程序设计题/C语言计算机二级考试押题版 与 数位 和 数 有关 求max与min 任意四个数 运算符和表达式版本 #include <stdio.h> int main( ) {int a,b,c,d;int max,min;printf("please input 4 integers:");scanf("%d%d%d%d", &a, &b, …...

Canonical标签在SEO中重要作用

canonical标签是很多搜索引擎都支持的一个标签&#xff0c;它的作用是标记某一网页的唯一url地址。这样做的目的是保证我们的某一网页在搜索引擎中只有一个唯一的地址。 Canonical标签对于一些入行不久的人来说&#xff0c;可能会有些陌生。但这个标签是很多搜索引擎都支持的标…...

【Linux之进程间通信】06.Linux进程通信 - 共享内存

【Linux之进程间通信】 项目代码获取&#xff1a;https://gitee.com/chenshao777/linux-processes.git &#xff08;麻烦点个免费的Star哦&#xff0c;您的Star就是我的写作动力&#xff01;&#xff09; 06.共享内存 共享内存是Linux进程间的通信方式之一 创建共享内存函数…...

oracle安装

服务端安装&#xff08;公司中不需要&#xff0c;只安装客户端就行&#xff09; 1、挂载一个Windows系统 双击vmx文件 启动 2、网络配置 添加一个网络 自己电脑看控制面板是否添加虚拟网卡 查看连接的网络&#xff0c;ip地址不能为1&#xff0c;为1就自己修改&#xff0c;…...

CSS样式的三种引入方式及优先级

说明&#xff1a;网页开发有三种技术&#xff0c;分别是html、css和js&#xff0c;分别对应页面的结构、表现和动作。css样式引入&#xff0c;是指把对页面的渲染作用到html上&#xff0c;有以下三种方式&#xff1a;行内式、内嵌式和外联式。 第一种&#xff1a;行内式&#…...

Linux第二天

上传 scp -r 本地文件路劲 用户名目标主机地址&#xff1a;路径 下载&#xff1a;scp -r 用户名目标主机地址&#xff1a;路径 本地目录 ls -A /root //查看root文件下所有的隐藏文件 命令&#xff1a;ls 选项&#xff1a; -l&#xff1a;查看文件属性 -h&#xff1a;文…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

解锁数据库简洁之道:FastAPI与SQLModel实战指南

在构建现代Web应用程序时&#xff0c;与数据库的交互无疑是核心环节。虽然传统的数据库操作方式&#xff08;如直接编写SQL语句与psycopg2交互&#xff09;赋予了我们精细的控制权&#xff0c;但在面对日益复杂的业务逻辑和快速迭代的需求时&#xff0c;这种方式的开发效率和可…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

Oracle11g安装包

Oracle 11g安装包 适用于windows系统&#xff0c;64位 下载路径 oracle 11g 安装包...

Android写一个捕获全局异常的工具类

项目开发和实际运行过程中难免会遇到异常发生&#xff0c;系统提供了一个可以捕获全局异常的工具Uncaughtexceptionhandler&#xff0c;它是Thread的子类&#xff08;就是package java.lang;里线程的Thread&#xff09;。本文将利用它将设备信息、报错信息以及错误的发生时间都…...

macOS 终端智能代理检测

&#x1f9e0; 终端智能代理检测&#xff1a;自动判断是否需要设置代理访问 GitHub 在开发中&#xff0c;使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新&#xff0c;例如&#xff1a; fatal: unable to access https://github.com/ohmyzsh/oh…...

ui框架-文件列表展示

ui框架-文件列表展示 介绍 UI框架的文件列表展示组件&#xff0c;可以展示文件夹&#xff0c;支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项&#xff0c;适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...