Android 文件管理器开发实战指南
摘要:本文从零开始,手把手带你构建一个高可用的 Android 文件管理器。内容涵盖项目环境搭建与权限配置、界面布局设计、目录加载与列表适配器、文件夹创建与重命名、删除与长按监听、复制粘贴机制、本地搜索服务、调用系统默认程序打开文件、内置文本编辑器与网页浏览器,以及常见运行时异常的排查与适配优化。全文以实战代码为主线,跳过理论堆砌,直接落地可运行的实现方案,帮助新手快速掌握文件管理器的核心开发路径。关键词:Android;文件管理器;Scoped Storage;RecyclerView;FileProvider;协程;权限适配在开发 Android 文件管理器时,很多开发者容易陷入一个误区:过分关注文件操作的底层 API,却忽视了用户体验的流畅性与系统权限的合规性。实际项目中,我们常遇到应用启动后无法读取存储卡、长按菜单响应迟钝、或者调用系统打开文件时崩溃等问题。这些痛点不仅影响功能完整性,更直接决定了用户是否愿意继续使用你的应用。尤其随着 Android 版本迭代,存储访问机制发生了巨大变化,从早期的直接路径访问到现在的 Scoped Storage,每一步都需要谨慎处理。如果你正在着手构建一个功能完备的文件管理工具,或者想优化现有项目的交互逻辑,那么本文分享的实战经验将非常有价值。我们将跳过理论堆砌,直接深入代码层面,从环境搭建到异常排查,完整还原一个高可用文件管理器的核心实现路径。目录① 项目环境搭建与权限配置要点② 界面布局设计与菜单初始化流程③ 目录内容加载与文件列表适配器实现④ 文件夹创建与文件重命名功能编码⑤ 文件删除操作与长按监听器逻辑⑥ 文件复制粘贴机制与剪贴板管理⑦ 本地文件搜索服务与广播接收器应用⑧ 调用系统默认程序打开各类文件⑨ 内置文本编辑器与网页浏览器实现⑩ 常见运行时异常排查与适配优化⑪ 完整实战代码:一个可运行的 Android 文件管理器① 项目环境搭建与权限配置要点启动一个新项目时,首要任务是明确目标 SDK 版本并配置相应的权限策略。目前主流做法是将targetSdkVersion设定为最新稳定版,同时在AndroidManifest.xml中声明必要的存储权限。对于 Android 10 及以上设备,必须适配分区存储机制,这意味着传统的WRITE_EXTERNAL_STORAGE权限在某些场景下不再生效,转而需要使用MediaStore或Storage Access Framework。在build.gradle中,建议将compileSdk与targetSdk设为当前最新稳定版(如 34),minSdk设为 21 以覆盖绝大多数设备。AndroidManifest.xml中按需声明权限,例如:uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"android:maxSdkVersion="32"/uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"android:maxSdkVersion="28"/这里用maxSdkVersion限制旧权限的生效范围:Android 10(API 29)及以上已默认启用分区存储,声明旧权限不仅无效,还可能引发审核问题;Android 13(API 33)起则改用细粒度的READ_MEDIA_IMAGES、READ_MEDIA_VIDEO、READ_MEDIA_AUDIO权限,需要按需申请。在代码初始化阶段,建议封装一个权限检查工具类。该类应在应用启动时主动检测当前权限状态,若未授权则引导用户跳转设置页。注意不要简单粗暴地请求所有权限,而是根据用户即将执行的操作动态申请。例如,仅在用户点击“新建文件夹”时才触发写入权限请求,这样能显著降低用户的抵触心理。此外,务必处理权限被永久拒绝的情况,提供友好的提示文案,避免应用陷入死循环。下面是一个基于协程的权限请求封装示例,按需申请并处理“永久拒绝”场景:classPermissionHelper(privatevalactivity:FragmentActivity){privatevallauncher=activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){result-valdenied=result.filter{!it.value}.keysif(denied.isNotEmpty()){valpermanentlyDenied=denied.any{!activity.shouldShowRequestPermissionRationale(it)}if(permanentlyDenied){// 引导用户去系统设置手动开启showSettingsDialog(activity)}else{// 用户可再次点击“重试”触发请求showRetryDialog(activity,denied)}}}funrequest(varargpermissions:String){launcher.launch(permissions.toList())}}调用时按操作动态申请,例如点击“新建文件夹”时只请求写入权限,点击“扫描图片”时才请求媒体读取权限,避免一次性弹出一堆授权框吓退用户。为帮助你更直观地理解版本差异,下表对比了 Android 10 以下与 Android 10+ 在存储权限、文件访问方式、URI 获取方式三个维度的核心区别:对比维度Android 10 以下(API 29)Android 10+(API ≥ 29)存储权限声明READ_EXTERNAL_STORAGE/WRITE_EXTERNAL_STORAGE即可直接读写外部存储默认启用分区存储,传统读写权限仅对媒体文件生效,需配合MediaStore或Storage Access Framework申请文件访问方式可直接通过File路径访问外部存储任意目录无法直接访问应用专属目录之外的路径,需通过MediaStore查询媒体文件,或用 SAF 的DocumentFile访问用户授权目录URI 获取方式可直接构造file://路径或Uri.fromFile()获取必须通过MediaStore的ContentResolver查询得到content://URI,或经 SAF 的ACTION_OPEN_DOCUMENT让用户选择后返回授权 URI简要说明:核心变化在于 Android 10+ 引入了分区存储(Scoped Storage),应用不再拥有对整个外部存储的任意读写权。因此,在适配新版本时,应优先使用MediaStore处理媒体文件、用 SAF 处理任意目录访问,并统一改用content://URI 传递文件,避免因路径或权限问题导致崩溃。② 界面布局设计与菜单初始化流程界面是用户感知应用质量的第一窗口。文件管理器通常采用经典的“左侧导航 + 右侧列表”或“顶部标签 + 内容区域”结构。推荐使用RecyclerView作为文件列表容器,配合ConstraintLayout实现灵活的自适应布局。在 XML 布局文件中,预定义好空状态视图(Empty View)和加载进度条,确保在网络延迟或目录为空时给用户明确反馈。下面是一个典型的文件列表布局骨架,使用SwipeRefreshLayout包裹RecyclerView,并预留空状态视图:androidx.swiperefreshlayout.widget.SwipeRefreshLayoutandroid:id="@+id/refreshLayout"android:layout_width="match_parent"android:layout_height="match_parent"androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/fileRecyclerView"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="8dp"android:clipToPadding="false"android:scrollbars="vertical"/TextViewandroid:id="@+id/emptyView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="center"android:text="当前目录为空"android:visibility="gone"//androidx.swiperefreshlayout.widget.SwipeRefreshLayout在 Activity 或 Fragment 中初始化时,设置LinearLayoutManager并绑定空状态切换逻辑:vallayoutManager=LinearLayoutManager(this)fileRecyclerView.layoutManager=layoutManager fileRecyclerView.adapter=fileAdapter// 数据为空时显示空状态视图funupdateEmptyState(isEmpty:Boolean){emptyView.visibility=if(isEmpty)View.VISIBLEelseView.GONE fileRecyclerView.visibility=if(isEmpty)View.GONEelseView.VISIBLE}SwipeRefreshLayout自带下拉刷新能力,配合setOnRefreshListener即可实现目录内容的手动刷新,无需额外引入第三方库。菜单初始化方面,可以利用PopupMenu或自定义Dialog来实现上下文操作菜单。当用户长按某项文件时,弹出包含“复制”、“移动”、“重命名”、“删除”等选项的菜单。关键在于菜单项的动态可见性:例如,对文件夹不应显示“用文本编辑器打开”,对只读文件应隐藏“删除”按钮。这需要在适配器层维护一份状态标记,并在菜单创建回调中实时判断。下面是一个基于PopupMenu的动态菜单实现,根据文件类型决定显示哪些操作项:funshowContextMenu(anchor:View,fileItem:FileItem){valpopup=PopupMenu(anchor.context,anchor)popup.menuInflater.inflate(R.menu.context_menu,popup.menu)// 动态控制菜单项可见性popup.menu.findItem(R.id.action_open_with).isVisible=fileItem.isFile popup.menu.findItem(R.id.action_rename).isVisible=truepopup.menu.findItem(R.id.action_delete).isVisible=!fileItem.isReadOnly popup.menu.findItem(R.id.action_edit_text).isVisible=fileItem.isFilefileItem.extensioninsetOf("txt","md","json","xml")popup.setOnMenuItemClickListener{item-when(item.itemId){R.id.action_open_with-openWith(fileItem)R.id.action_rename-showRenameDialog(fileItem)R.id.action_delete-confirmDelete(fileItem)R.id.action_edit_text-openTextEditor(fileItem)else-false}}popup.show()}对应的res/menu/context_menu.xml定义如下:menuxmlns:android="http://schemas.android.com/apk/res/android"itemandroid:id="@+id/action_open_with"android:title="用其他应用打开"/itemandroid:id="@+id/action_edit_text"android:title="用文本编辑器打开"/itemandroid:id="@+id/action_rename"android:title="重命名"/itemandroid:id="@+id/action_delete"android:title="删除"//menu在适配器的onBindViewHolder中为每个 item 设置setOnLongClickListener,长按时调用showContextMenu即可。这样菜单项始终与当前文件类型匹配,避免出现“对文件夹显示文本编辑”这类逻辑错误。③ 目录内容加载与文件列表适配器实现数据加载是文件管理器的核心引擎。我们需要编写一个异步任务或使用协程来扫描指定目录下的所有文件和子文件夹,避免阻塞主线程导致界面卡顿。扫描结果应封装成统一的FileItem数据模型,包含文件名、路径、大小、修改时间及类型标识。首先定义一个轻量的数据模型,用于在列表与适配器之间传递文件信息:dataclassFileItem(valname:String,valpath:String,valsize:Long,vallastModified:Long,valisDirectory:Boolean){valextension:Stringget()=if(isDirectory)""elsename.substringAfterLast('.',"").lowercase()valisFile:Booleanget()=!isDirectory}目录扫描建议放在协程的Dispatchers.IO中执行,避免阻塞主线程。下面是一个基于协程的扫描封装,支持按需取消并返回排序后的结果:suspendfunscanDirectory(path:String):ListFileItem=withContext(Dispatchers.IO){valdir=File(path)if(!dir.exists()||!dir.isDirectory)return@withContextemptyList()dir.listFiles()?.map{file-FileItem(name=file.name,path=file.absolutePath,size=if(file.isFile)file.length()else0L,lastModified=file.lastModified(),isDirectory=file.isDirectory)}?.sortedWith(compareByDescendingFileItem{it.isDirectory}.thenBy{it.name.lowercase()})?:emptyList()}在 ViewModel 或 Fragment 中调用时,通过viewModelScope.launch启动扫描,并在完成后更新列表数据。若目录较大,可结合yield()分批让出 CPU,保证界面始终流畅。适配器(Adapter)的实现决定了列表的渲染效率。继承RecyclerView.Adapter并重写onBindViewHolder方法,根据文件类型动态加载不同的图标资源。为了提升滚动流畅度,务必在 ViewHolder 中缓存视图引用,并利用 Glide 或 Coil 等库异步加载缩略图(针对图片视频文件)。下面是一个完整的FileAdapter实现,包含 ViewHolder 缓存、类型图标切换与点击/长按回调:classFileAdapter(privatevalonItemClick:(FileItem)-Unit,privatevalonItemLongClick:(FileItem)-Unit):RecyclerView.AdapterFileAdapter.FileViewHolder(){privatevalitems=mutableListOfFileItem()funsubmitList(newItems:ListFileItem){items.clear()items.addAll(newItems)notifyDataSetChanged()}overridefunonCreateViewHolder(parent:ViewGroup,viewType:Int):FileViewHolder{valbinding=ItemFileBinding.inflate(LayoutInflater.from(parent.context),parent,false)returnFileViewHolder(binding)}overridefunonBindViewHolder(holder:FileViewHolder,position:Int){holder.bind(items[position])}overridefungetItemCount():Int=items.sizeinnerclassFileViewHolder(privatevalbinding:ItemFileBinding):RecyclerView.ViewHolder(binding.root){funbind(item:FileItem){binding.tvName.text=item.name binding.tvInfo.text=if(item.isDirectory){"文件夹 ·${formatSize(item.size)}"}else{"${item.extension.uppercase()}·${formatSize(item.size)}"}binding.ivIcon.setImageResource(if(item.isDirectory)R.drawable.ic_folderelseR.drawable.ic_file)binding.root.setOnClickListener{onItemClick(item)}binding.root.setOnLongClickListener{onItemLongClick(item)true}}}privatefunformatSize(size:Long):String{valkb=size/1024.0returnwhen{kb1-"$sizeB"kb1024-String.format("%.1f KB",kb)else-String.format("%.1f MB",kb/1024)}}}同时,实现一个简单的排序逻辑,允许用户按名称、时间或大小对列表进行升序/降序排列。可以在submitList前传入排序方式,例如:funsortBy(comparator:ComparatorFileItem){items.sortWith(comparator)notifyDataSetChanged()}// 按名称排序sortBy(compareBy{it.name.lowercase()})// 按修改时间倒序sortBy(compareByDescending{it.lastModified})// 按大小倒序sortBy(compareByDescending{it.size})这样数据加载、列表渲染与排序逻辑彼此解耦,后续新增排序维度或切换视图模式时,只需扩展适配器即可,无需改动扫描逻辑。④ 文件夹创建与文件重命名功能编码新建文件夹功能看似简单,实则涉及路径合法性校验。在接收到用户输入的文件夹名称后,首先需过滤非法字符(如/ \ : * ? " |),然后调用File.mkdir()或Files.createDirectory()执行创建。若返回失败,应立即捕获异常并向用户展示具体原因,如“名称已存在”或“磁盘空间不足”。下面是一个完整的创建文件夹封装,包含名称校验、非法字符过滤与结果反馈:funcreateFolder(parentPath:String,name:String):Boolean{// 1. 过滤非法字符valinvalidChars=setOf('/','\\',':','*','?','"','','','|')valcleanName=name.filterNot{itininvalidChars}.trim()if(cleanName.isEmpty()){Toast.makeText(context,"文件夹名称不能为空或仅含非法字符",Toast.LENGTH_SHORT).show()returnfalse}// 2. 检查是否已存在同名文件夹valtarget=File(parentPath,cleanName)if(target.exists()){Toast.makeText(context,"同名文件夹已存在",Toast.LENGTH_SHORT).show()returnfalse}// 3. 执行创建并反馈结果returntry{valcreated=target.mkdirs()if(created){Toast.makeText(context,"文件夹创建成功",Toast.LENGTH_SHORT).show()}else{Toast.makeText(context,"创建失败,请检查磁盘空间",Toast.LENGTH_SHORT).show()}created}catch(e:SecurityException){Log.e(TAG,"createFolder: 权限不足",e)Toast.makeText(context,"没有写入权限",Toast.LENGTH_SHORT).show()false}}在 UI 层,通过AlertDialog弹出输入框,让用户输入新文件夹名称,确认后调用上述方法:funshowCreateFolderDialog(parentPath:String){valinput=EditText(this).apply{hint="请输入文件夹名称"inputType=InputType.TYPE_CLASS_TEXT}AlertDialog.Builder(this).setTitle("新建文件夹").setView(input).setPositiveButton("创建"){_,_-valname=input.text.toString()if(createFolder(parentPath,name)){refreshCurrentDirectory()// 创建成功后刷新列表}}.setNegativeButton("取消",null).show()}这里使用mkdirs()而非mkdir(),它能一次性创建多级不存在的父目录,避免因父目录缺失导致创建失败。文件重命名逻辑类似,但多了一步原子性操作的要求。使用File.renameTo()方法时,需注意该方法在不同文件系统上的行为差异,部分情况下可能返回 false 但未抛出异常。更稳健的做法是使用 NIO 包的Files.move(),并指定StandardCopyOption.ATOMIC_MOVE以确保操作的原子性。下面是一个基于 NIO 的重命名封装,兼顾原子性与错误反馈:funrenameFile(file:File,newName:String):Boolean{// 1. 校验新名称合法性valinvalidChars=setOf('/','\\',':','*','?','"','','','|')valcleanName=newName.filterNot{itininvalidChars}.trim()if(cleanName.isEmpty()){Toast.makeText(context,"文件名不能为空或仅含非法字符",Toast.LENGTH_SHORT).show()returnfalse}// 2. 目标路径valtarget=File(file.parentFile,cleanName)if(target.exists()){Toast.makeText(context,"同名文件已存在",Toast.LENGTH_SHORT).show()returnfalse}// 3. 使用 NIO 原子移动returntry{Files.move(file.toPath(),target.toPath(),StandardCopyOption.ATOMIC_MOVE)Toast.makeText(context,"重命名成功",Toast.LENGTH_SHORT).show()true}catch(e:AtomicMoveNotSupportedException){// 部分文件系统不支持原子移动,降级为普通移动try{Files.move(file.toPath(),target.toPath())Toast.makeText(context,"重命名

相关新闻

MapReduce父子关系挖掘:从海量数据到层级关系链的工程实践

MapReduce父子关系挖掘:从海量数据到层级关系链的工程实践

1. 从"谁是谁的爹"说起:一个被低估的经典问题"使用MapReduce挖掘父子关系"这个标题,第一次看到的人可能会觉得有点摸不着头脑——父子关系有什么好挖的?这不是数据库里一个外键就搞定的事吗?但如果你真正处理…

2026/10/17 16:03:21 阅读更多 →
IndexTTS-1.5-MLX推理环境搭建指南:uv + huggingface + mlx-indextts三步搞定

IndexTTS-1.5-MLX推理环境搭建指南:uv + huggingface + mlx-indextts三步搞定

【免费下载链接】IndexTTS-1.5-MLX 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/IndexTTS-1.5-MLX 点击查看 免费下载 IndexTTS-1.5-MLX 是把零样本语音克隆 TTS 系统 IndexTTS-1.5 转换为 MLX 格式的模型仓库,专为 Apple Silicon Mac …

2026/10/17 16:03:21 阅读更多 →
GLM-5.3-Flash-NVFP4凭什么撑住1M上下文?mHC流形约束超连接机制完整拆解

GLM-5.3-Flash-NVFP4凭什么撑住1M上下文?mHC流形约束超连接机制完整拆解

大模型模型量化多模态本地部署 【免费下载链接】GLM-5.3-Flash-NVFP4 项目地址: https://ai.gitcode.com/hf_mirrors/nvidia/GLM-5.3-Flash-NVFP4 点击查看 免费下载 GLM-5.3-Flash-NVFP4 是 NVIDIA 基于 Model Optimizer 对 ZAI 的 GLM-5.3-Flash 进行 NVFP4 4-bi…

2026/10/17 16:03:21 阅读更多 →

最新新闻

代码化制图实战:从拖拽画布到 diagram-design 设计系统

代码化制图实战:从拖拽画布到 diagram-design 设计系统

说白了,"diagram-design"这个项目,就是一套用代码画架构图、流程图和数据流转图的设计体系。我自己维护过几套不同风格的项目文档,深知画图的痛:用绘图软件拖控件调对齐线,一调就是半小时,图表稍…

2026/10/17 16:54:53 阅读更多 →
OpenCode终端AI编程助手:安装、模型接入与实战

OpenCode终端AI编程助手:安装、模型接入与实战

说实话,我一开始对 OpenCode 是有点“又一个终端 AI 工具”的冷淡态度的,毕竟 Claude Code、Codex CLI 已经够折腾了。但真正把 OpenCode 安装到 Linux 工作机上、又跑完一个真实项目的 bug 修复之后,我改观了:它确实是一个更开放…

2026/10/17 16:54:53 阅读更多 →
AI辅助毕业论文全流程实测:宏智树AI测评

AI辅助毕业论文全流程实测:宏智树AI测评

毕业论文季一到,后台私信里问得最多的问题就是“AI写论文哪个软件最好用”。说实话,每次看到这种问题我都想反问一句:你是想彻底躺平让AI代写,还是想在每个环节找个得力帮手?这两者的使用方式、工具选择、甚至风险完全…

2026/10/17 16:54:53 阅读更多 →
Java TCP编程实战:从Socket到高并发,踩坑与排障全指南

Java TCP编程实战:从Socket到高并发,踩坑与排障全指南

很多Java开发者每天都在和HTTP接口打交道,但HTTP底下那层TCP协议,真要自己动手写过Socket通信的人,反而没几个。我这些年做过不少Java网络通信相关的项目,从简单的设备接入、文件传输,到高并发推送服务,发现…

2026/10/17 16:54:53 阅读更多 →
Java课程设计必备:森林冰火人单人版Swing小游戏源码解析

Java课程设计必备:森林冰火人单人版Swing小游戏源码解析

简介:一份基于Java开发的森林冰火人单人版小游戏完整源码包,面向Java初学者、游戏开发爱好者及课程设计学生,可用于学习Swing/JavaFX界面搭建、键盘事件处理、游戏循环、重力跳跃与碰撞检测等基础机制。压缩包共78个文件,其中含6个…

2026/10/17 16:54:53 阅读更多 →
图表即代码:用文本描述构建可维护的架构图工作流

图表即代码:用文本描述构建可维护的架构图工作流

1. 从“diagram-design”这个标题说起:它到底在解决什么问题 第一次看到“diagram-design”这个标题,很多人会下意识觉得它是个画图工具,或者某个前端组件库。但如果你真正做过技术方案评审、系统架构梳理、或者给非技术同事讲清楚一个复杂流…

2026/10/17 16:53:52 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →