写得了代码,焊得了板!嵌入式开发工程师必修之代码管理方案(中)
目录
2.2 分仓、权限与依赖问题
2.3 基于 Git 进行多仓管理
Git submodule
Git subtree
Script/CMake
Git-Repo
Conan
本文来自
武让 极狐GitLab 高级解决方案架构师
🌟 前一篇文章,作者介绍了嵌入式开发场景的代码管理特点与诉求,以及该场景下的代码管理工具与方式之 SVN 与 Git。前情回顾 👉 嵌入式开发场景下的代码管理方案(上)
本文承上启下,将介绍嵌入式开发场景的代码管理分仓、权限与依赖问题,以及基于 Git 的多仓管理。
2.2 分仓、权限与依赖问题
在上文中我已经简单介绍了 SVN 和 Git 在分仓模式和权限管理上的一些区别,简单来说:
-
SVN 支持目录授权,常用于大仓模式;
-
Git 仅支持仓库授权,常用于分仓模式,也支持大仓模式。
这本是一个简单的选择题:要么留在 SVN,保留现有的目录授权模式;要么使用 Git 分仓,权限也落在不同的仓库上;要么使用 Git 大仓,权限就控制在整个仓库上;直到另一个需求打破了这个平衡:代码复用。
做过 C/C++ 且又做过 Java、Python、Node 等语言开发的技术人员常常会感叹 C/C++ 缺少好的包管理工具,羡慕 Java 有 Maven、Python 有 Pip、Node 有 Npm,而 C/C++ 一直深陷 DLL 地狱、代码版本与交付版本不一致、重复造轮子等各式各样依赖问题的泥潭,不可自拔。
首先 C/C++ 由于其语言特性,构建时常常是系统底层相关,所以打包时需要考虑操作系统、体系架构、编译器版本、构建类型等一系列因素。
且需要关注一些包自身的属性:纯头文件库、静态库还是动态库,以及包的构建参数(比如优化级别、是否开启 exception 和 rtti 的编译选项等),还有指定裁剪性(特性宏)等配置。
另外,由于 C/C++ 的标准库(glibc 和 libstdc++)存在版本兼容性问题,以及 C++ 存在 ABI 兼容性问题,这会让包的版本管理超越语义化版本(SemVer)所能解决的问题范围,导致包的创建者需要在发包的时候为包的兼容性做更多的考虑。
最后,由于 C/C++ 语言在语法上缺乏包级别的模块化机制,会让包的符号冲突以及依赖解决变得困难。如果还不够,再加上交叉编译的场景,绝对会让一个通用 C/C++ 包管理器的复杂度超过其它任何语言。
包管理器的目的就是对包进行版本控制,解决项目间的依赖问题,也能从根本上解决代码复用的问题。但由于 C/C++ 包管理器的复杂度,导致 C/C++ 开发人员在过去很长一段时间内没有包管理工具可用。在这样的背景下,大家对于 C/C++ 的代码复用发展出了很多模式:
-
基于代码文件目录划分
项目划分好模块,定义好自己的目录,协商出一个 Common 目录作为公共的头文件目录,然后对不同的开发人员分配不同的目录权限就可以分工协作了。
看起来是不是非常眼熟,这就是 SVN 的使用方式。然而这个 Common 目录可能又需要被另一个项目 B 所引用,那么项目 B 整个代码也加进这个代码库。最后所有的模块都耦合到一起,代码库膨胀的很快,导致严重的性能问题。
-
基于代码复用工具划分
由于 SVN 性能问题,很多开发者开始尝试迁移到 Git,把代码分不到不同的代码库中。但由于没有包管理工具,嵌入式的项目需要先将项目关联的代码库拉到一起,然后再构建。而 Git 本身不提供仓库之间的关联关系,这就对分库之后的聚合管理提出了需求。后来出现了 git submodule
、git subtree
、git repo
等工具,就是为了解决分仓后,如何把项目再聚合出来,从而实现项目管理和代码复用。
但这些都是在代码文件级别的复用,增加了管理的复杂度。
-
基于 CMake
一些构建工具的发展,为 C/C++ 的代码复用引入了更好的方式。例如 CMake 从 3.0 版本开始被称之为“Modern CMake”,是因为它引入了 target 的概念,以及基于 target 建立起了构建的依赖可见性和传播控制机制。这些都更好的支持了代码在构建上的模块化,借助 CMake 的 ExternalProject 和 find_package 特性,使得我们可以从指定的 http 或者 git 分支下载、构建、安装和引用代码库。
但是这种复用方式,对于间接依赖的管理仍旧是不足的,没有办法做到全链条的依赖解析、依赖追溯、冲突判决,以及基于变更进行最小范围的重构建和发布管理。
-
基于包管理工具
解铃还须系铃人,问题发展到最后还是回到问题本身,C/C++ 没有好的包管理工具,那就做一个。
Conan 是一款出色的开源 C/C++ 包管理器。它吸收了很多现代化包管理器的设计思想,探索解决通用 C/C++ 包管理器的各种挑战。它需要使用 Python 进行配置,目前在国内的普及度还不算高,相关的文档教程也不是很齐全,相对来说有一定的门槛,但 Conan 可以说是目前 C/C++ 唯一可用的包管理工具,也可能是真正的破局者。
这就是为什么一些软件企业从 SVN 迁移到 Git 没有那么大阻力,而从事嵌入式开发的企业则不同的原因。归根到底是 C/C++ 缺乏好的依赖管理手段,而企业、管理者、开发人员一直都面临代码复用这个问题,并希望通过从 SVN 迁移到 Git 来解决这个问题。但显然这个问题仅依靠 SVN 或者 Git 自身是无法解决的。
2.3 基于 Git 进行多仓管理
既然 Git 现在是代码管理的主流方案,并且依靠 Git 自身无法解决分仓后的多仓管理问题和代码复用问题,那就需要借助一些其他的工具和方法,其实都是上文中提到过的。虽然这些工具和方法本身不够完善,但对于处于不同阶段不同场景的企业和用户,可以有个参考,毕竟软件世界没有银弹。
Git submodule
Git submodule 可以让一个 Git 仓库作为另一个仓库的子目录,从而实现在一个代码库中引用其他的代码库进行复用。
Git submodule 的特点如下:
-
在主库中通过
git submodule add <子库 git 地址>
命令实现引用子库代码; -
在主库中通过
.gitmodule
文件来记录主库和子库的引用关系。
-
主库只是引用了子库的 SHA,并没有直接拷贝子库代码,所以子库的代码变更内容在主库上不可见,只是在本地拉取时将对应的子库拉取到本地。所以在 Git 服务器上看不到完整的项目代码,这也意味着无法实现对于整个项目的代码评审。
-
Clone 主库不会自动 Clone 子库,除非在 Clone 主库时:
执行
git submodule update
;执行
git clone --recursive
;添加 Git 全局配置
git config --global submodule.recurse true
。 -
子库
commit/push
也需要在主库pull/commit/push
,容易遗忘导致代码未同步或者主库关联了旧的子库:可在主库执行
git submodule foreach 'git pull origin master'
更新所有子库;由于该问题导致主库、子库在解决冲突、切换分支时变得非常复杂,且容易出错。
个人不建议在实际项目中使用 Git submodule,除非能有效解决以上问题,或者可在少量的项目中进行试用再进行决策。
Git subtree
Git subtree 与 Git submodule 功能类似,但目前 Git subtree 在开发人员中的呼声高于 Git submodule。
Git subtree 的特点如下:
-
在主库中通过
git subtree add --prefix=<主库子目录> <子库git地址> <子库分支>
命令实现引用子库代码。
-
主库拷贝了子库的代码,所以在 Git 服务器上可以看到完整的项目代码,也可以实现整个项目的代码评审。所以
Git submodule is Link, Git subtree is Copy
. 也意味着 Git subtree 的性能略差,会增加主库的大小。
-
无法通过默认的 Git 命令将主库的代码变更同步到子库,需要适应新的工作流。
# 添加子库
git subtree add --prefix=<主库子目录> <子库git地址> <子库分支>
# 从子库中拉取
git subtree pull --prefix=<主库子目录> <子库git地址> <子库分支>
# 推送到子库
git subtree push --prefix=<主库子目录> <子库git地址> <子库分支>
-
可通过一些工具和方法简化工作流:
-
设置 Git别名以简化操作:
# 在 .gitconfig 文件中添加
[alias] gits = subtree
# 然后执行命令
gits add --prefix=<主库子目录> <子库git地址> <子库分支>
2. 设置子库为主库的远端别名以简化操作:
# 添加子库为主库的remote别名
git remote add -f subA <subA>.git
# 然后执行命令
git subtree add --prefix=A subA master
git subtree pull --prefix=A subA master
3. 使用第三方工具git-subrepo。
个人建议可以在依赖场景不复杂的中小型项目中使用 Git subtree,以避免性能问题,它的体验和工作方式相对比较友好。
Script/CMake
最简单的办法往往最有效,通过脚本来拉取或者相关子库的代码,将脚本放在主库中,按需执行,比如拉取相关子库代码:
git clone -b <子库A分支> <子库A git地址> <本地目录A>
git clone -b <子库B分支> <子库B git地址> <本地目录B>
或者通过 CMake 的 FetchContent 来实现,可以参考《C++ 工程依赖管理新方向:CMake & Git | KC 的废墟堆》,基于 FetchContent 可以再封装一套脚本。
个人建议也是可以在依赖场景不复杂的中小型项目中使用,比较轻量和灵活,但有一定的技术门槛,甚至需要专人来做,这对做传统嵌入式开发的团队是个挑战。
Git-Repo
Git-Repo 是 Google 开源的一款 Git 客户端工具,是为了搭配 Google 开源的代码管理工具 Gerrit 进行使用,而 Gerrit 是为了管理 Android 的开源项目 AOSP 而设计的。
Google 是为数不多的坚持大仓模式(Monorepo)的巨头公司,AOSP 也是一个大型项目,一个项目包含了数百个代码库,彼此之间存在依赖关系。所以为了更好的管理这些仓库,Google 形成了自己独特的 AOSP 工作流,Gerrit 通过一个项目清单 Manifest.xml
来组织仓库关系,Git-Repo 就可以通过 Manifest.xml
来实现代码的批量拉取和推送。
Git-Repo 和 Gerrit 主要是解决了多仓管理的问题,除了对仓库进行批量操作,Gerrit 还支持跨代码库进行评审,所以 AOSP 从流程到系统到工具都是相辅相成的。Git-Repo 可以在一定程度上解决代码复用问题,不过 Gerrit 本身不是商业化产品,没有厂商技术支持,且 Gerrit 的用户体验较差,复杂度较高,所以当嵌入式项目使用 AOSP 专用的工具,又显得有点水土不服。
借鉴 Git-Repo 和 Manifest.xml
的思想,阿里使用 Golang 重写了一个 Git-Repo-Go 工具,可以在 GitLab/极狐GitLab、GitHub 等以 Git 为底层的代码管理系统上获得 Git-Repo 批量操作代码库的体验。
但是上文中也提到,Git-Repo 和 Gerrit 是相辅相成的,Gerrit 支持跨代码库进行代码评审,支持更丰富的权限管理模式,为多仓下的代码管理和评审提供了基础。而 GitLab/极狐GitLab、GitHub 等代码管理系统目前还是以分仓模式为主,原生不提供这种业务功能,所以导致 Git-Repo-Go 仅仅是实现了 Git-Repo 的部分功能,这时不免怀疑这么折腾为啥不直接用 Gerrit。
Conan
终极方案,如果项目依赖相对复杂,需要在项目级别进行代码评审,且要考虑依赖解析、循环依赖、依赖追踪等问题,那么以上工具方案都不用考虑了,它们都无法从根本上解决问题,所以 Conan 这个工具必须死磕下来,不管是头文件、静态库还是动态库的管理,Conan 都能在一定程度上满足,虽然它本身具备一定的复杂性,但目前没有更好的路可以走了。
当然如果愿意快速解决问题,知名制品库厂商 JFrog 提供了 Conan Center 以及相关解决方案,我就不多打广告了。如果愿意折腾,Conan 本身开源,且可以通过 SonaType 的开源制品库 Nexsus 实现,这也变相提供了另一种“低成本”的方案。
💡 后续推送剧透:围绕企业对于嵌入式开发场景的诉求,极狐GitLab 提供了一整套解决方案,可以较好的解决嵌入式开发场景下的种种问题,下期将为你介绍。
欢迎订阅关注~
相关文章:
写得了代码,焊得了板!嵌入式开发工程师必修之代码管理方案(中)
目录 2.2 分仓、权限与依赖问题 2.3 基于 Git 进行多仓管理 Git submodule Git subtree Script/CMake Git-Repo Conan 本文来自 武让 极狐GitLab 高级解决方案架构师 🌟 前一篇文章,作者介绍了嵌入式开发场景的代码管理特点与诉求,以及…...
Interlij IDEA 运行 ruoyi 后端项目。错误: 找不到或无法加载主类 com.ruoyi.auth.RuoYiAuthApplication
错误: 找不到或无法加载主类 com.ruoyi.auth.RuoYiAuthApplication 用了 IDEA运行,参考以下issue删除.idea目录也没有用 (官方文档写是用Eclipse运行) 错误: 找不到或无法加载主类 com.ruoyi.auth.RuoYiAuthApplication Issue #I48N2X 若依/RuoYi-C…...
相机设置报错记录
Camera->SetPosition(0.0, -980, 0.0);Camera->SetFocalPoint(0.0, 0.0, 0.0);Camera->SetViewUp(0.0, 1.0, 0.0);上述代码出现错误提示Resetting view-up since view plane normal is parallel,这个时候是viewup方向与投影方向平行了,而出现的…...
Vue3中搜索表单的二次封装
最近使用Vue3ElementPlus开发项目,从整体上构思组件的封装。能写成组件的内容都进行封装,方便多个地方使用。 受AntDesign的启发,在项目中有搜索表单table分页的地方可以封装为一个组件,只需要对组件传入table的列,组成…...
百度23Q2财报最新发布:营收利润加速增长,AI+生态战略渐显规模
百度集团-SW(9888.HK)Q2财报已于2023/08/22(美东)盘前发布,二季度百度集团整体收入实现341亿元,同比增长15%;归属百度的净利润(non-GAAP)达到80亿元,同比增长44%。营收和利润双双实现大幅增长,超市场预期。其中,百度核…...
一个pdf文件分割成两个
# -- coding: utf-8 --** import PyPDF2 # 打开原始PDF文件 # with open(zhongguojinxiandaishi.pdf, rb) as pdf_file: # pdf_reader PyPDF2.PdfReader(pdf_file) # num_pages len(pdf_reader.pages) # # # 确定分割点(例如,将页面一分为二࿰…...
Android 保存图片
这个主要讲的InputStream去保存。 如果需要BItmap与InputStream相互转换可以参考 Android Bitmap、InputStream、Drawable、byte[]、Base64之间的转换关系 保存图片我们需要考虑系统版本,Q前后还是不一样的。 /*** 保存图片* param context 上下文* param inputS…...
Android相机-架构
引言: 主要是针对CameraAPI v2 HAL3的架构对Android相机系统进行梳理。 相机架构 App和FrameWork Camera API v2位于: packages/apps/Camer2 frameworks/ex/camera2 应用框架级别,使用Camera2 API与相机的硬件进行交互。通过调用Binder接口…...
从C语言到C++_33(C++11_上)initializer_list+右值引用+完美转发+移动构造/赋值
目录 1. 列表初始化initializer_list 2. 前面提到的一些知识点 2.1 小语法 2.2 STL中的一些变化 3. 右值和右值引用 3.1 右值和右值引用概念 3.2 右值引用类型的左值属性 3.3 左值引用与右值引用比较 3.4 右值引用的使用场景 3.4.1 左值引用的功能和短板 3.4.2 移动…...
如何在Linux系统中处理PDF文件?
如何在Linux系统中处理PDF文件? 1.查看PDF文档2.合并PDF文档3.压缩PDF文档4.提取PDF文本 PDF文件是一种特殊的文件格式,它可以在不同的操作系统中实现跨平台的文件传输和共享。Linux系统作为一种自由开放的操作系统,拥有丰富的PDF文件处理工具…...
SpringBoot实现热部署/加载
在我们修改完项目代码后希望不用重启服务器就能把项目代码部署到服务器中(也就是说修改完项目代码后不用重启服务器修改后的项目代码就能生效)。 一、实现devtools原理 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-…...
我是如何使用Spring Retry减少1000 行代码
使用 Spring Retry 重构代码的综合指南。 问题介绍 在我的日常工作中,我主要负责开发一个庞大的金融应用程序。当客户发送请求时,我们使用他们的用户 ID 从第三方服务获取他们的帐户信息,保存交易并更新缓存中的详细信息。尽管整个流程看起来…...
ARM开发(stm32 cortex-A7核IIC实验)
1.实验目标:采集温湿度传感器值; 2.分析框图(模拟IIC控制器); 3.代码; ---iic.h封装时序协议头文件--- #ifndef __IIC_H__ #define __IIC_H__ #include "stm32mp1xx_gpio.h" #include "st…...
「Java」《Java集合框架详解:掌握常用集合类,提升开发效率》
Java集合框架详解:掌握常用集合类,提升开发效率 摘要:一. 引言二. 集合框架概述三. 集合接口详解四. 集合类的选择五. 泛型和类型安全六. 集合的线程安全七. 高级集合类和算法八、Java集合实践操作示例1. 创建和初始化集合:2. 遍历…...
游戏出海需知:Admob游戏广告变现策略
越来越多的出海游戏公司更加重视应用内的广告变现,而 AdMob因为其提供的丰富的广告资源,稳定平台支持,被广泛接入采用。 Admob推出的广告变现策略包括bidding、插页式激励视频、开屏广告、各种细分功能的报告等等。 一、Bidding 竞价策略 …...
【linux】NFS调试总结
文章目录 00. ENV10. 简述20. 下载、安装、配置30. 使用1. 从uboot中设置NFS启动文件系统2. 调试 80. 问题1. NFS版本不匹配问题 90. 附件91. 服务端NFS配置项简述 00. ENV ubuntn1804 10. 简述 百度百科:https://baike.baidu.com/item/%E7%BD%91%E7%BB%9C%E6%96%87…...
wireshark进行网络监听
一、实验目的: 1)掌握使用CCProxy配置代理服务器; 2)掌握使用wireshark抓取数据包; 3)能够对数据包进行简单的分析。 二、预备知识: 包括监听模式、代理服务器、中间人攻击等知识点…...
时间复杂度
一、时间复杂度 时间复杂度是计算机科学中用来衡量算法运行时间随输入规模增加而增长的速度。简单来说,它是一个衡量算法执行效率的指标,表示算法运行所需时间与输入数据量之间的关系。 时间复杂度通常用大O符号(O)来表示&#…...
Unity实现广告滚动播放、循环播放、鼠标切换的效果
效果: 场景结构: 特殊物体:panel下面用排列组件horizent layout group放置多个需要显示的面板,用mask遮罩好。 using System.Collections; using System.Collections.Generic; using DG.Tweening; using UnityEngine; using Unity…...
LangChain + Streamlit + Llama:将对话式AI引入本地机器
推荐:使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 什么是LLMS? 大型语言模型 (LLM) 是指能够生成与人类语言非常相似的文本并以自然方式理解提示的机器学习模型。这些模型使用包括书籍、文章、网站和其他来源在内的…...
Python 读写 Excel 文件库推荐和使用教程
文章目录 前言Python 读写 Excel 库简介openpyxl 处理 Excel 文件教程pandas 处理 Excel 文件教程总结 前言 Python 读写 Excel 文件的库总体看还是很多的, 各有其优缺点, 以下用一图总结各库的优缺点, 同时对整体友好的库重点介绍其使用教程…...
“深入解析JVM:理解Java虚拟机的工作原理和优化技巧“
标题:深入解析JVM:理解Java虚拟机的工作原理和优化技巧 摘要:本文将深入探讨Java虚拟机(JVM)的工作原理和优化技巧。我们将从JVM的基本结构开始,逐步介绍其工作原理,并提供一些实际示例代码&am…...
解决SEGGER Embedded Studio无法显示Nordic MCU外设寄存器问题
如果使用SES调试NRF52840的时候发现,官方例程只能显示CPU寄存器,但是无法显示外设寄存器时,解决办法如下: 1.在解决方案右键→Options→Debug→Debugger,然后Target Device选择正确的型号。 2.Register Definition Fil…...
Oracle-day1:scott用户、查询、取整、截取、模糊查询、别名——23/8/23
整理一下第一天软件测试培训的知识点 1、scott用户 -- 以system管理员登录锁定scott用户 alter user scott account lock;-- 以system管理员登录解锁scott用户 alter user scott account unlock;-- 以system管理员用户设置scott用户密码 alter user scott identfied by tiger…...
stm32之3.key开关
假设key电阻为40kΩ,则key0 的电压3.3v*4/52.64v 2.key开关代码 ② GPIO_OType_PP//推挽输出 GPIO_OType_PP//开漏输出 推挽输出是指输出端口可以同时提供高电平和低电平输出,而开漏输出则是指输出端口只能提供低电平输出,高电平时需要借…...
GPT带我学-设计模式-代理模式
什么是代理模式 代理模式(Proxy Pattern)是设计模式中的一种结构型模式,它为其他对象提供一种代理以控制对这个对象的访问。 代理模式有三个主要角色:抽象主题(Subject)、真实主题(Real Subje…...
VMware Workstation Pro 无法使用开机状态下拍的快照来克隆虚拟机,怎么解决?
环境: VMware Workstation Pro16.0 Win10 专业版 问题描述: VMware Workstation Pro有台虚拟机在开机状态下拍了个6.7快照这个win10初始版,现在想在这个快照下直接克隆,无法使用开机状态下拍的快照创建克隆 解决方案: 1.关闭当前虚拟机 2.到虚拟机文件夹复制一份Wind…...
【JAVA】XML及其解析技术、XML检索技术、设计模式
XML XML(Extensible Markup Language)是可扩展标记语言的缩写,它是一种数据表示格式,可以描述复杂的数据结构,常用于传输和存储数据 作用: 用于进行存储数据和传输数据作为软件的配置文件 第一行是文档声明 <?xml version&q…...
Ansible 自动化安装软件
例子如下: 创建一个名为/ansible/package.yml 的 playbook : 将 php 和 mariadb 软件包安装到 dev、test 和 prod 主机组中的主机上 将 RPM Development Tools 软件包组安装到 dev 主机组中的主机上 将 dev 主机组中主机上的所有软件包更新为最新版本 --- - name:…...
简单介绍 React Native 整合 Formik 实现表单校验
Formik 是 React 和 React Native 开源表单库,Formik 负责处理重复且烦人的事情——跟踪值/错误/访问的字段、编排验证和处理提交——所以您不必这样做。而简化字段校验的话我们可以使用yup工具来实现。 首先安装Formik 和 Yup npm i formik npm i yupFormik 与 R…...
58同城网络营销靠谱吗/优化疫情防控 这些措施你应该知道
内核是操作系统最基础也是最重要的部分。下图为 RT-Thread 内核架构图,内核处于硬件层之上,内核部分包括内核库、实时内核实现。 内核库是为了保证内核能够独立运行的一套小型的类似 C 库的函数实现子集。 这部分根据编译器的不同自带 C 库的情况也会有…...
wordpress网站 添加微信/一手渠道推广平台
首先简述一下自动化测试对于数据库的应用场景:无论在接口自动化还是UI自动化的测试中,我们都需要准备一些测试数据,类似于账号信息。比如我们需要一个未注册的手机号,我们不能保证给出的测试数据是未注册的,这个时候就…...
响应式企业网站 下载/网推和地推的区别
定义 TCHAR :通过define 定义的字符串宏 因为C支持两种字符串:常规的ANSI编码 (使用""包裹)、Unicode编码(使用L" "包裹)。因此对应的有两套字符串处理函数。 比如:strlen …...
做网站和开发app有什么不同/搜狗搜索网页版
【安装】Windows下Oracle安装图解----oracle-win-64-11g 详细安装步骤 一、 Oracle 下载 官方下地址 http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html win 32位操作系统 下载地址: http://download.oracle.com/otn/nt/orac…...
东莞茶山网站建设/百度关键词首页排名怎么上
最近推荐一位日本女明星——石原里美 封面就是其本人 有颜有才 笑起来真的很好看了 希望大家能与我一起欣赏她的美 啊哈哈哈哈哈哈哈哈 补一句:我不是超级无敌屌丝猥琐男哈!!! 给定一个可能包含重复元素的整数数组 nums&…...
网站建设竞标书/百度seo教程
FileUtils类的应用 写入一个文件;从文件中读取;创建一个文件夹,包括文件夹;复制文件和文件夹;删除文件和文件夹;从URL地址中获取文件;通过文件过滤器和扩展名列出文件和文件夹;比较…...