纯前端本地文件管理器(VSCode风格)(浏览器对本地文件增删改查)

纯前端本地文件管理器(VSCode风格)(浏览器对本地文件增删改查)

简介

本项目为一个纯前端实现的本地文件管理器网页(index.html),可在 Chrome/Edge 浏览器中直接打开,具备类似 VSCode 的本地文件夹操作体验。
无需后端,所有功能均在浏览器端实现。


主要功能

  1. 选择本地文件夹

    • 用户点击左上角文件夹按钮,授权后可浏览和操作本地文件夹内容。
  2. 文件树展示

    • 以树形结构展示所选文件夹下的所有文件和子文件夹。
    • 文件夹和文件有不同图标区分。
    • 文件夹默认收缩,点击可展开/收缩子项。
    • 每个目录下,文件夹排在前,文件排在后,均按名称排序。
  3. 文件/文件夹操作

    • 新建文件、新建文件夹(在当前选中目录下)
    • 编辑文件(支持多语言代码高亮,编辑区为 CodeMirror 5)
    • 保存文件
    • 删除文件/文件夹(支持递归删除文件夹)
    • 重命名文件/文件夹(文件夹为递归复制+删除实现)
  4. 编辑器体验

    • 编辑区为 CodeMirror 5,支持多种主流编程语言高亮(js、py、html、css、md、c/c++/java等)。
    • 编辑区可编辑,支持行号、自动换行。
    • 保存按钮为图标形式,点击后将编辑内容写回本地文件。
  5. 界面与交互

    • 所有操作按钮均为小图标,无文字,简洁美观。
    • 文件树和编辑区自适应布局,支持多层嵌套目录。
    • 状态栏实时提示操作结果(如保存成功、删除失败等)。

技术说明

  • 前端技术:原生 HTML + CSS + JavaScript
  • 代码高亮:CodeMirror 5(通过 unpkg CDN 引入)
  • 本地文件操作:File System Access API(需用户授权,支持 Chrome/Edge)
  • 无需后端,所有数据均在本地浏览器内存和本地文件系统中操作

使用方法

  1. 用 Chrome 或 Edge 浏览器打开 index.html
  2. 点击左上角“选择文件夹”图标,授权访问本地文件夹
  3. 在左侧文件树中浏览、增删改查文件和文件夹
  4. 编辑文件后,点击保存图标即可写回本地

注意事项

  • 仅支持支持 File System Access API 的浏览器(如 Chrome、Edge)
  • 仅能操作用户授权的文件夹及其子文件
  • 由于浏览器安全限制,网页无法自动访问任意本地文件夹,需每次手动授权
  • 编辑器高亮支持的语言可根据需要扩展

依赖

  • CodeMirror 5
    通过 unpkg CDN 引入,无需本地安装

主要文件结构

  • index.html
    主页面,包含所有功能和样式,无需其他依赖文件

如需二次开发或自定义功能,可直接修改 index.html,所有逻辑均在本文件内实现。
如需支持更多语言高亮,可在 <head> 中引入更多 CodeMirror 5 的 mode 脚本。


代码如下 :

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>本地文件管理器 Demo</title><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>body { font-family: Arial, sans-serif; margin: 0; padding: 0; background: #f5f5f5; }header { background: #222; color: #fff; padding: 0.2em; text-align: center;  display: flex; justify-content: center; align-items: center;}#container { display: flex; height: 90vh; }#sidebar { width: 320px; background: #fff; border-right: 1px solid #ddd; overflow-y: auto; padding: 1em; }#main { flex: 1; padding: 1em; display: flex; flex-direction: column; }#fileTree ul { list-style: none; padding-left: 1em; }#fileTree li { margin: 2px 0; cursor: pointer; display: flex; flex-direction: column; align-items: stretch; }#fileTree .row { display: flex; align-items: center; }#fileTree li.selected { background: #e0e7ff; }.actions { margin-left: auto; display: flex; }.actions button { background: none; border: none; padding: 2px; margin-right: 2px; cursor: pointer; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; }.actions button:last-child { margin-right: 0; }.actions button svg { width: 18px; height: 18px; }#editor { flex: 1; width: 100%; margin-top: 1em; font-family: monospace; font-size: 1em; }#saveBtn { margin-top: 0.5em; background: none; border: none; cursor: pointer; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; }#saveBtn svg { width: 22px; height: 22px; }.folder { font-weight: bold; }.file { color: #333; }.hidden { display: none; }#status { color: #888; font-size: 0.9em; margin-top: 0.5em; }#toolbar { margin-bottom: 1em; display: flex; }#toolbar button { background: none; border: none; margin-right: 0.5em; cursor: pointer; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; }#toolbar button svg { width: 22px; height: 22px; }.tree-icon { width: 18px; height: 18px; margin-right: 4px; flex-shrink: 0; }.caret { width: 14px; height: 14px; margin-right: 2px; transition: transform 0.2s; }.caret.collapsed { transform: rotate(-90deg); }.caret.expanded { transform: rotate(0deg); }.caret.invisible { opacity: 0; }</style><!-- CodeMirror 5 --><link rel="stylesheet" href="https://unpkg.com/codemirror@5.65.16/lib/codemirror.css"><script src="https://unpkg.com/codemirror@5.65.16/lib/codemirror.js"></script><script src="https://unpkg.com/codemirror@5.65.16/mode/javascript/javascript.js"></script><script src="https://unpkg.com/codemirror@5.65.16/mode/python/python.js"></script><script src="https://unpkg.com/codemirror@5.65.16/mode/htmlmixed/htmlmixed.js"></script><script src="https://unpkg.com/codemirror@5.65.16/mode/css/css.js"></script><script src="https://unpkg.com/codemirror@5.65.16/mode/xml/xml.js"></script><script src="https://unpkg.com/codemirror@5.65.16/mode/markdown/markdown.js"></script><script src="https://unpkg.com/codemirror@5.65.16/mode/clike/clike.js"></script>
</head>
<body><header><h2>本地文件管理器 Demo</h2><div>(仅支持 Chrome/Edge,需授权访问本地文件夹)</div></header><div id="container"><div id="sidebar"><div id="toolbar"><button id="pickFolderBtn" title="选择文件夹"><svg viewBox="0 0 20 20" fill="none"><path d="M2 5a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5z" stroke="#333" stroke-width="1.5"/></svg></button><button id="newFileBtn" title="新建文件" disabled><svg viewBox="0 0 20 20" fill="none"><path d="M4 4h8l4 4v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2z" stroke="#333" stroke-width="1.5"/><path d="M12 4v4h4" stroke="#333" stroke-width="1.5"/><path d="M10 9v6" stroke="#333" stroke-width="1.5"/><path d="M7 12h6" stroke="#333" stroke-width="1.5"/></svg></button><button id="newFolderBtn" title="新建文件夹" disabled><svg viewBox="0 0 20 20" fill="none"><path d="M2 6a2 2 0 0 1 2-2h4l2 2h6a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V6z" stroke="#333" stroke-width="1.5"/><path d="M7 10h6" stroke="#333" stroke-width="1.5"/><path d="M10 7v6" stroke="#333" stroke-width="1.5"/></svg></button></div><div id="fileTree"></div></div><div id="main"><div id="fileInfo"></div><textarea id="editor" class="hidden" style="height: 100%; min-height: 300px;"></textarea><button id="saveBtn" class="hidden" title="保存"><svg viewBox="0 0 20 20" fill="none"><path d="M4 4h12v12H4V4z" stroke="#333" stroke-width="1.5"/><path d="M7 4v4h6V4" stroke="#333" stroke-width="1.5"/><path d="M7 12h6" stroke="#333" stroke-width="1.5"/></svg></button><div id="status"></div></div></div><script>let rootHandle = null;let currentFileHandle = null;let currentDirHandle = null;let selectedLi = null;const pickFolderBtn = document.getElementById('pickFolderBtn');const newFileBtn = document.getElementById('newFileBtn');const newFolderBtn = document.getElementById('newFolderBtn');const fileTree = document.getElementById('fileTree');const editorTextarea = document.getElementById('editor');const saveBtn = document.getElementById('saveBtn');const fileInfo = document.getElementById('fileInfo');const status = document.getElementById('status');let cm = null;// 语言模式映射function getMode(filename) {const ext = filename.split('.').pop().toLowerCase();if (["js", "jsx", "ts", "tsx", "cjs", "mjs"].includes(ext)) return "javascript";if (["py"].includes(ext)) return "python";if (["html", "htm"].includes(ext)) return "htmlmixed";if (["css", "scss", "less"].includes(ext)) return "css";if (["json"].includes(ext)) return "javascript";if (["md", "markdown"].includes(ext)) return "markdown";if (["c", "cpp", "h", "hpp", "java"].includes(ext)) return "clike";return "javascript"; // 默认js}// 初始化CodeMirror 5function showEditor(text, filename) {editorTextarea.classList.remove('hidden');if (cm) {cm.toTextArea();cm = null;}cm = CodeMirror.fromTextArea(editorTextarea, {value: text,mode: getMode(filename),lineNumbers: true,lineWrapping: true,theme: 'default',indentUnit: 2,tabSize: 2,autofocus: true,});cm.setValue(text);setTimeout(() => cm.refresh(), 0);}// 工具函数function escapeHtml(str) {return str.replace(/[&<>"']/g, c => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]));}// 选择文件夹pickFolderBtn.onclick = async () => {try {rootHandle = await window.showDirectoryPicker();fileTree.innerHTML = '';await renderTree(rootHandle, fileTree);status.textContent = '已选择文件夹';newFileBtn.disabled = false;newFolderBtn.disabled = false;hideEditor();fileInfo.textContent = '';} catch (e) {status.textContent = '未选择文件夹';}};// 渲染文件树async function renderTree(dirHandle, container, path = '', collapsed = true) {container.innerHTML = '';const ul = document.createElement('ul');// 收集所有 entriesconst entries = [];for await (const [name, handle] of dirHandle.entries()) {entries.push({ name, handle });}// 文件夹在前,文件在后,按名称排序entries.sort((a, b) => {if (a.handle.kind !== b.handle.kind) {return a.handle.kind === 'directory' ? -1 : 1;}return a.name.localeCompare(b.name, 'zh-Hans-CN');});for (const { name, handle } of entries) {const li = document.createElement('li');const row = document.createElement('div');row.className = 'row';// 图标let icon;if (handle.kind === 'directory') {icon = document.createElement('span');icon.innerHTML = `<svg class="tree-icon" viewBox="0 0 20 20" fill="none"><rect x="3" y="5" width="14" height="10" rx="2" stroke="#fbbf24" stroke-width="1.5" fill="#fde68a"/></svg>`;} else {icon = document.createElement('span');icon.innerHTML = `<svg class="tree-icon" viewBox="0 0 20 20" fill="none"><rect x="4" y="3" width="12" height="14" rx="2" stroke="#60a5fa" stroke-width="1.5" fill="#dbeafe"/></svg>`;}// 展开/收缩箭头let caret = null;if (handle.kind === 'directory') {caret = document.createElement('span');caret.innerHTML = `<svg class="caret collapsed" viewBox="0 0 20 20"><polyline points="7,8 13,10 7,12" fill="none" stroke="#888" stroke-width="2"/></svg>`;caret.classList.add('caret', 'collapsed');} else {caret = document.createElement('span');caret.classList.add('caret', 'invisible');}row.appendChild(caret);row.appendChild(icon);// 名称const nameSpan = document.createElement('span');nameSpan.textContent = name;nameSpan.style.flex = '1';nameSpan.style.userSelect = 'none';nameSpan.className = handle.kind;row.appendChild(nameSpan);li.title = name;li.dataset.path = path + '/' + name;li.classList.add(handle.kind);// 操作按钮const actions = document.createElement('span');actions.className = 'actions';if (handle.kind === 'file') {const editBtn = document.createElement('button');editBtn.title = '编辑';editBtn.innerHTML = `<svg viewBox="0 0 20 20"><path d="M4 13.5V16h2.5l7.1-7.1a1 1 0 0 0 0-1.4l-2.1-2.1a1 1 0 0 0-1.4 0L4 13.5z" stroke="#333" stroke-width="1.2" fill="#fffbe6"/></svg>`;editBtn.onclick = e => { e.stopPropagation(); openFile(handle, li); };actions.appendChild(editBtn);}const renameBtn = document.createElement('button');renameBtn.title = '重命名';renameBtn.innerHTML = `<svg viewBox="0 0 20 20"><path d="M4 13.5V16h2.5l7.1-7.1a1 1 0 0 0 0-1.4l-2.1-2.1a1 1 0 0 0-1.4 0L4 13.5z" stroke="#6366f1" stroke-width="1.2" fill="#eef2ff"/></svg>`;renameBtn.onclick = e => { e.stopPropagation(); renameEntry(handle, dirHandle, name); };actions.appendChild(renameBtn);const delBtn = document.createElement('button');delBtn.title = '删除';delBtn.innerHTML = `<svg viewBox="0 0 20 20"><rect x="5" y="7" width="10" height="8" rx="2" stroke="#ef4444" stroke-width="1.5" fill="#fee2e2"/><path d="M8 9v4M12 9v4" stroke="#ef4444" stroke-width="1.2"/></svg>`;delBtn.onclick = e => { e.stopPropagation(); deleteEntry(handle, dirHandle, name); };actions.appendChild(delBtn);row.appendChild(actions);li.appendChild(row);// 点击选中/展开收缩if (handle.kind === 'directory') {let expanded = false;let subUl = document.createElement('ul');subUl.style.display = 'none';li.appendChild(subUl);nameSpan.onclick = async e => {e.stopPropagation();expanded = !expanded;if (expanded) {caret.classList.remove('collapsed');caret.classList.add('expanded');subUl.style.display = '';await renderTree(handle, subUl, path + '/' + name, false);} else {caret.classList.remove('expanded');caret.classList.add('collapsed');subUl.style.display = 'none';}};// 支持选中li.onclick = e => {e.stopPropagation();if (selectedLi) selectedLi.classList.remove('selected');li.classList.add('selected');selectedLi = li;currentDirHandle = handle;currentFileHandle = null;hideEditor();fileInfo.textContent = '文件夹: ' + name;};} else {// 文件点击选中并编辑nameSpan.onclick = e => {e.stopPropagation();openFile(handle, li);};}ul.appendChild(li);}container.appendChild(ul);}// 打开文件async function openFile(fileHandle, li) {try {const file = await fileHandle.getFile();const text = await file.text();showEditor(text, file.name);saveBtn.classList.remove('hidden');fileInfo.textContent = '文件: ' + file.name;currentFileHandle = fileHandle;currentDirHandle = null;if (selectedLi) selectedLi.classList.remove('selected');if (li) { li.classList.add('selected'); selectedLi = li; }} catch (e) {status.textContent = '无法打开文件: ' + e.message;}}// 保存文件saveBtn.onclick = async () => {if (!currentFileHandle) return;try {const writable = await currentFileHandle.createWritable();const value = cm ? cm.getValue() : '';await writable.write(value);await writable.close();status.textContent = '保存成功';} catch (e) {status.textContent = '保存失败: ' + e.message;}};// 新建文件newFileBtn.onclick = async () => {if (!rootHandle) return;let dir = currentDirHandle || rootHandle;const name = prompt('输入新文件名:');if (!name) return;try {const fileHandle = await dir.getFileHandle(name, { create: true });await renderTree(rootHandle, fileTree);status.textContent = '新建文件成功';// 新建后自动打开openFile(fileHandle, null);} catch (e) {status.textContent = '新建文件失败: ' + e.message;}};// 新建文件夹newFolderBtn.onclick = async () => {if (!rootHandle) return;let dir = currentDirHandle || rootHandle;const name = prompt('输入新文件夹名:');if (!name) return;try {await dir.getDirectoryHandle(name, { create: true });await renderTree(rootHandle, fileTree);status.textContent = '新建文件夹成功';} catch (e) {status.textContent = '新建文件夹失败: ' + e.message;}};// 删除文件/文件夹async function deleteEntry(handle, parentHandle, name) {if (!confirm('确定要删除 ' + name + ' 吗?')) return;try {await parentHandle.removeEntry(name, { recursive: handle.kind === 'directory' });await renderTree(rootHandle, fileTree);status.textContent = '删除成功';hideEditor();fileInfo.textContent = '';} catch (e) {status.textContent = '删除失败: ' + e.message;}}// 重命名文件/文件夹async function renameEntry(handle, parentHandle, oldName) {const newName = prompt('输入新名称:', oldName);if (!newName || newName === oldName) return;try {// 只能通过新建+复制+删除实现if (handle.kind === 'file') {const file = await handle.getFile();const newHandle = await parentHandle.getFileHandle(newName, { create: true });const writable = await newHandle.createWritable();await writable.write(await file.text());await writable.close();} else {// 文件夹递归复制await copyDirectory(handle, parentHandle, newName);}await parentHandle.removeEntry(oldName, { recursive: true });await renderTree(rootHandle, fileTree);status.textContent = '重命名成功';} catch (e) {status.textContent = '重命名失败: ' + e.message;}}// 递归复制文件夹async function copyDirectory(srcHandle, destParent, newName) {const newDir = await destParent.getDirectoryHandle(newName, { create: true });for await (const [name, handle] of srcHandle.entries()) {if (handle.kind === 'file') {const file = await handle.getFile();const newFile = await newDir.getFileHandle(name, { create: true });const writable = await newFile.createWritable();await writable.write(await file.text());await writable.close();} else {await copyDirectory(handle, newDir, name);}}}// 隐藏编辑器function hideEditor() {if (cm) {cm.toTextArea();cm = null;}editorTextarea.classList.add('hidden');}</script>
</body>
</html> 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.tpcf.cn/pingmian/86961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

windows安装wsl、Ubuntu、docker desktop

以下是Windows安装WSL&#xff08;Windows Subsystem for Linux&#xff09;及在Ubuntu中配置使用Docker的完整流程&#xff0c;整合了最新官方方案和常见问题解决方案&#xff1a; &#x1f527; 一、Windows安装WSL&#xff08;推荐WSL 2&#xff09; &#x1f4cd; 安装前提…

华为云Flexus+DeepSeek征文|云端智能加持:华为云ModelArts Studio提升Chat2DB的AI数据库管理效能

华为云FlexusDeepSeek征文&#xff5c;云端智能加持&#xff1a;华为云ModelArts Studio提升Chat2DB的AI数据库管理效能 前言一、华为云ModelArts Studio平台介绍1.1 ModelArts Studio介绍1.2 ModelArts Studio主要特点1.3 ModelArts Studio使用场景1.4 ModelArts Studio产品架…

微信小程序封装loading 修改

1. custom-loading.vue <template><view v-if"visible" class"custom-loading-mask" touchmove.stop.prevent><view class"custom-loading-container"><!-- 动态点点 --><text class"loading-text">{…

Windows环境下Docker容器化的安装与设置指南

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; 系统要求与准备工作 在开始安装和配置 Docker 之前&#xff0c;需要确保您的 Windows 系统满足以下要求&#xff1a; 操作系统版本&#xff1a;推荐使用 Windows 10 或更高版本&#xff0c;特别是 64 位版本。对…

0 数学习题本

零 引言 数学错题与好题总结 一 基础阶段 1 高数部分 习题册:武忠祥 660 1️⃣ 函数 极限 连续 2️⃣ 一元微分 3️⃣ 一元积分 4️⃣ 微分方程 5️⃣ 多元微分 6️⃣ 二重积分 7️⃣ 无穷级数 8️⃣ 空间几何 9️⃣ 多元积分 2 线代部分 习题册:汤家凤 1800 1️⃣ 行列式…

USB服务器的5个核心价值

USB服务器&#xff08;USB Server&#xff09;是一款专为企业级环境设计的创新型硬件解决方案&#xff0c;其核心使命在于解决物理USB设备&#xff08;如U盾、加密狗、身份认证Key等&#xff09;在分布式办公、远程协作及复杂IT架构中面临的接入、管理与安全难题。本文以朝天椒…

基于vue3+ByteMD快速搭建自己的Markdown文档编辑器

简介 ByteMD 是一个轻量级、功能丰富的 Markdown 编辑器组件&#xff0c;由稀土掘金&#xff08;juejin.cn&#xff09;团队开发并开源。它采用 Svelte 构建&#xff0c;支持双向编辑&#xff08;所见即所得&#xff09;&#xff0c;并提供了丰富的插件系统。 核心特点 轻量…

“AI大语言模型”助力大气科学:ERA5再分析数据、WRF处理、遥感降水、CMIP6未来气候、天气晴雨预测的完整方法论等

内容覆盖使用GPT处理数据、生成论文摘要、文献综述、技术方法分析等实战案例&#xff0c;将AI技术广泛应用于科研工作。特别关注将GPT与Python结合应用于遥感降水数据处理、ERA5大气再分析数据的统计分析、干旱监测及风能和太阳能资源评估等大气科学关键场景。旨在提升参与者在…

STM32给FPGA的外挂FLASH进行升级

STM32给FPGA的外挂FLASH进行升级 一、电路方案设计二、软件写FLASH三、解决第一次烧录后FPGA无法启动的问题 前言&#xff1a; 一个复杂的嵌入式中&#xff0c;如果对某些实时性要求极高的情况下势必会使用到FPGA来保证&#xff0c;这里面牵扯到给FPGA的程序升级问题&#xff0…

Python 数据分析与可视化 Day 9 - 缺失值与异常值处理技巧

✅ 今日目标 熟练处理数据中的缺失值&#xff08;NaN、None&#xff09;学会识别和处理异常值&#xff08;outliers&#xff09;掌握常用的处理方法&#xff1a;填充、删除、替换、标准差法、箱型图法等为后续机器学习建模打好数据清洗基础 &#x1f4da; 一、缺失值处理&…

概述-1-数据库的相关概念

数据库的相关概念 用户通过SQL操作数据库管理系统&#xff0c;再通过数据库管理系统操作数据库以及数据库中的数据。 数据库 数据库是存储数据的仓库, 数据是有组织的进行存储, DataBase简称&#xff08;DB&#xff09; 数据库管理系统 操纵和管理数据库的大型软件, DataB…

可视化大屏展示

可视化大屏是一种将大量数据进行整合、分析&#xff0c;并以直观、形象的可视化方式展示在大屏幕上的信息展示系统。主要组成部分分为2个&#xff1a;硬件设备、软件系统。 一、大屏价值 1、数据可视化&#xff1a;将复杂的数据转化为直观的图形、图表和地图等&#xff0c;使数…

服务器被入侵的常见迹象有哪些?

&#x1f6a8; 服务器被入侵的常见迹象 &#x1f7e2; 一、系统和资源异常 CPU、内存或网络流量异常飙高 即使没有业务负载&#xff0c;资源长期占满。 磁盘空间突然被写满 可疑大文件或日志暴涨。 系统负载显著升高 uptime、top 显示 load average 异常。 &#x1f7e1;…

日本生活:日语语言学校-日语作文-沟通无国界(5)-题目:我的一天

日本生活&#xff1a;日语语言学校-日语作文-沟通无国界&#xff08;5&#xff09;-题目&#xff1a;我的一天 1-前言2-作文原稿3-作文日语和译本&#xff08;1&#xff09;日文原文&#xff08;2&#xff09;对应中文&#xff08;3&#xff09;对应英文 4-老师评语5-自我感想&…

前端领域的技术热点与深度解析

&#x1f525; 一、框架革新&#xff1a;React、Vue、Svelte 的进化方向 React 19 实验版 Server Components 深化&#xff1a;支持流式渲染与异步状态管理&#xff0c;SSR 性能提升40%。 并发模式优化&#xff1a;减少渲染阻塞&#xff0c;复杂交互场景延迟降低35%。 Vue 3…

【unity游戏开发——网络】网络游戏通信方案——强联网游戏(Socket长连接)、 弱联网游戏(HTTP短连接)

注意&#xff1a;考虑到热更新的内容比较多&#xff0c;我将热更新的内容分开&#xff0c;并全部整合放在【unity游戏开发——网络】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 一、联网游戏类型划分二、核心通信协议对比三、开发选择指南专栏推荐完结 …

Java-60 深入浅出 分布式服务Paxos 算法优化 如何保证Paxos算法的活性

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月16日更新到&#xff1a; AI炼丹日志-29 - 字节…

一阶线性双曲型偏微分方程组的特征值与通解分析

问题3 求系统 U u + A U x = 0 U_u + A U_x = 0 Uu​+AUx​=0 的特征并写出通解,其中矩阵 A A A 如下: A 1 = ( 3 2 1 0 2 1 0 0 1 ) , A 2 = ( 3 2 1 0 2 1 0 0 − 1 ) , A_1 = \begin{pmatrix} 3 & 2 & 1 \\ 0 & 2 & 1 \\ 0 & 0 & 1 \end{pmatr…

解锁AI无限潜能!景联文科技数据产品矩阵再升级:多语言题库、海量语料、垂域代码库,全面赋能大模型训练

景联文科技持续聚焦AI数据需求前沿&#xff0c;全新发布包含中文题库数据集、英文题库数据集、算法代码数据库、英文语料、中文语料、垂直领域数据、小语种数据在内的七大高质量数据集产品系列。 此次发布的数据集覆盖广泛的应用场景&#xff0c;通过严格的清洗与结构化处理&am…

OSPF(开放最短路径优先)

一、ospf简介 OSPF是基于链路状态的内部网关协议&#xff0c;与距离矢量协议不同&#xff0c;链路状态协议通告的是链路状态而不是路由表。OSPF是用于自治系统&#xff08;AS&#xff09;内部的路由决策,特点有&#xff0c;收敛速度快&#xff0c;安全性好&#xff0c;避免环路…