FTP判断目录是否存在:协议原理与多语言实操方案

1. 项目概述:为什么“FTP判断目录是否存在”这件事值得单独写一篇深度实操笔记

在日常运维、自动化脚本开发、CI/CD流程编排,甚至是一些老旧系统对接场景中,“检查远程FTP服务器上某个路径是否存在”看似是个微不足道的小动作,但恰恰是大量脚本卡住、任务失败、日志报错的隐形源头。我做过不下二十个跨部门协作项目,其中近三分之一的交付延期,最初都追溯到一句简单的if [ -d /remote/path ]在FTP上下文中根本无效——因为Shell的文件测试操作符只作用于本地文件系统,对FTP协议完全失能。这不是语法错误,而是协议层的认知错位。

核心关键词“FTP判断目录是否存在”,背后实际承载的是三个不可回避的现实需求:第一,非交互式自动化校验——脚本不能弹窗、不能人工确认,必须返回明确的布尔值(存在/不存在);第二,兼容性兜底能力——目标FTP服务可能是纯FTP(无TLS)、FTPES(显式加密)、甚至某些定制化嵌入式设备的精简FTP实现,连ls -l输出格式都可能不标准;第三,资源与容错平衡——不能为查一个目录就建立三次连接、耗时5秒以上,也不能因超时设置过短而误判“不存在”。

适合谁来读?如果你正在写部署脚本、做定时同步任务、维护遗留系统接口,或者刚接手一个用Python+ftplib写了一半却总在cwd()时报error_perm: 550的项目,那这篇就是为你写的。它不讲FTP协议RFC文档里的理论分层,只聚焦“今天下午三点前,让我的脚本稳稳跑通”。接下来我会从设计逻辑、协议细节、语言级实现、异常陷阱四个维度,把这件事掰开揉碎——包括为什么NLST比LIST更可靠、为什么SIZE命令能绕过权限限制、以及某次在银行后台系统里用PWD+字符串匹配硬生生扛过3年零故障的真实案例。

2. 协议层原理与方案选型:不是所有“查目录”的方法都叫“判断存在”

2.1 FTP协议本身没有“exists”语义,所有判断都是间接推断

这是最根本的认知前提。FTP协议(RFC 959及后续扩展)定义的命令集中,没有任何一个原生命令用于查询路径存在性。CWD(Change Working Directory)用于切换目录,LIST用于列出内容,NLST用于仅列出名称,STAT用于获取状态——但它们的返回码和行为高度依赖服务端实现。比如:

  • 某些FTP服务器对不存在的目录执行CWD时返回550(Requested action not taken),但另一些老版本会返回501(Syntax error in parameters);
  • LIST /nonexist在ProFTPD上可能直接断连,在Pure-FTPd上返回空列表加226 Transfer complete;
  • SIZE /nonexist/file.txt对文件有效,但对目录多数返回550,可偏偏有些嵌入式设备对目录也返回213 0(假装目录是0字节文件)。

因此,“判断存在”本质是利用服务端对非法路径的响应差异,结合客户端对响应码、响应文本、连接状态的综合解析。这决定了方案必须包含三重验证:响应码主判断 + 响应文本辅助校验 + 连接稳定性兜底。

2.2 四种主流技术路径对比:为什么推荐“CWD+PWD”组合

我们实测了四种常见方案在27种FTP服务端(vsftpd、ProFTPD、Pure-FTPd、FileZilla Server、Windows IIS FTP、各类NAS内置FTP等)上的表现,结果汇总如下表:

方案核心命令成功率平均耗时(ms)主要失效场景维护成本
CWD+PWD(推荐)CWD target_dir→PWD98.1%120~350目录名含空格且未转义低(标准命令,无解析逻辑)
LIST解析LIST target_dir82.4%480~1200服务端禁用LIST、目录为空、中文名乱码高(需正则匹配不同格式)
NLST解析NLST target_dir76.9%320~850服务端禁用NLST、返回非标准分隔符中(需处理多行拼接)
SIZE试探SIZE target_dir63.2%210~600目录被识别为文件、权限严格拒绝低但误判率高

提示:“CWD+PWD”方案的逻辑是:先尝试切换到目标目录,若成功则PWD必能返回当前路径(含目标目录名);若失败则捕获550等错误码。关键在于PWD命令本身几乎在所有FTP实现中都可用,且返回格式高度统一(257 "/path/to/dir" is current directory.)。即使CWD失败,连接通常保持活跃,可立即执行下一次操作。

2.3 为什么放弃“被动模式+数据连接”方案?

有开发者提出用被动模式(PASV)建立数据连接后,向LIST命令发送请求并监听数据端口是否可连接——这理论上能区分“目录不存在”和“权限不足”。但我们实测发现:

  • 在企业防火墙环境下,PASV模式的数据端口常被拦截,导致连接超时而非协议错误;
  • 某些云存储网关(如S3 FTP桥接层)对PASV响应227 Entering Passive Mode (10,0,0,1,123,45)后,实际数据端口映射失败,客户端永远等不到数据连接;
  • 实现复杂度陡增:需解析227响应提取IP/端口、建立新TCP连接、处理SSL/TLS协商(若启用)、读取数据流并解析——而一个目录存在性判断本不该触发如此重的链路。

注意:除非你的场景明确要求区分“不存在”和“无权限”,否则主动模式(PORT)下的控制通道判断已足够鲁棒。现代FTP库(如Python的ftplib)默认使用主动模式,且可通过ftp.set_pasv(False)强制关闭PASV。

3. 多语言实现实战:从Python到Shell,覆盖生产环境高频场景

3.1 Python ftplib方案:兼顾健壮性与可读性的工业级实现

Python的ftplib是FTP操作的事实标准库,但其默认行为存在坑点:login()后不自动处理编码、cwd()失败不抛异常、pwd()返回值含多余引号。以下代码经过3年线上项目验证,已封装为可直接复用的函数:

import ftplib import socket from typing import Optional, Tuple def ftp_directory_exists( host: str, username: str, password: str, directory: str, port: int = 21, timeout: float = 10.0, encoding: str = "utf-8" ) -> Tuple[bool, str]: """ 判断FTP服务器上指定目录是否存在 Args: host: FTP服务器地址 username: 用户名 password: 密码 directory: 待检查的目录路径(支持相对路径如'./subdir',绝对路径如'/pub/data') port: FTP端口,默认21 timeout: 连接与命令超时时间(秒) encoding: FTP协议文本编码,默认UTF-8(部分旧系统需设为'latin-1') Returns: Tuple[bool, str]: (是否存在, 详细信息或错误消息) """ ftp = None try: # 1. 建立连接并登录 ftp = ftplib.FTP() ftp.connect(host, port, timeout=timeout) ftp.login(username, password) ftp.encoding = encoding # 关键!解决中文路径问题 # 2. 处理路径标准化:移除末尾斜杠,避免重复切换 clean_dir = directory.rstrip('/') if not clean_dir: return True, "Root directory always exists" # 3. 尝试切换到目标目录 try: ftp.cwd(clean_dir) # 切换成功后,用PWD确认当前路径是否包含目标目录名 # 避免因软链接或挂载点导致的误判 pwd_response = ftp.pwd() # 标准化PWD返回值:提取引号内路径(如 '257 "/pub/data" is current directory.') import re match = re.search(r'257\s+"([^"]+)"', pwd_response) if match and clean_dir in match.group(1) or match.group(1).rstrip('/') == clean_dir: return True, f"Directory exists: {clean_dir}" else: return False, f"PWD mismatch: expected '{clean_dir}', got '{match.group(1) if match else 'unknown'}'" except ftplib.error_perm as e: # 捕获550等权限错误,明确标识不存在 if "550" in str(e): return False, f"Directory not found: {clean_dir} ({str(e)})" else: return False, f"Permission denied or other error: {str(e)}" except ftplib.all_errors as e: return False, f"FTP error during CWD: {str(e)}" except (socket.timeout, socket.error) as e: return False, f"Connection failed: {str(e)}" except Exception as e: return False, f"Unexpected error: {str(e)}" finally: if ftp: try: ftp.quit() except: ftp.close() # 使用示例 if __name__ == "__main__": exists, msg = ftp_directory_exists( host="ftp.example.com", username="user", password="pass", directory="/data/reports/2024", timeout=15.0 ) print(f"Exists: {exists}, Message: {msg}")

关键细节说明:

  • ftp.encoding = encoding解决了90%的中文路径乱码问题,旧系统设为'latin-1'即可;
  • re.search(r'257\s+"([^"]+)"', pwd_response)正则精准提取PWD返回的路径,避免服务端返回文本格式差异(如257 "/path" is current directory.或257 "/path");
  • 对clean_dir进行rstrip('/')处理,防止/data//这类路径导致cwd()失败;
  • finally块确保连接无论成功失败都会释放,避免FTP服务器连接数耗尽。

3.2 Shell脚本方案:无Python环境时的轻量级替代

在嵌入式设备、Docker Alpine镜像或CI流水线中,常需纯Shell方案。lftp工具比原生ftp命令强大得多,支持脚本化和错误码返回:

#!/bin/sh # check_ftp_dir.sh FTP_HOST="ftp.example.com" FTP_USER="user" FTP_PASS="pass" CHECK_DIR="/data/logs" # 使用lftp执行目录存在性检查 # -c 执行命令,-e 设置环境变量,-p 指定端口 RESULT=$(lftp -c " set ftp:ssl-allow false; set net:max-retries 2; set net:timeout 10; open ftp://$FTP_USER:$FTP_PASS@$FTP_HOST; cd $CHECK_DIR 2>/dev/null; echo \$?; " 2>/dev/null) # lftp cd成功返回0,失败返回非0(通常是1) if [ "$RESULT" = "0" ]; then echo "Directory exists: $CHECK_DIR" exit 0 else echo "Directory does not exist or access denied: $CHECK_DIR" exit 1 fi

注意事项:

  • 必须安装lftp(apk add lftp或apt-get install lftp),它比系统自带ftp命令更可靠;
  • set ftp:ssl-allow false禁用SSL避免TLS握手失败(若服务端不支持FTPS);
  • set net:max-retries 2防止网络抖动导致误判;
  • cd $CHECK_DIR 2>/dev/null将错误输出丢弃,只捕获退出码,避免日志污染。

3.3 PowerShell方案:Windows服务器管理员的必备技能

在混合IT环境中,PowerShell是连接Windows生态的桥梁。以下脚本使用.NET Framework的FtpWebRequest类,无需额外模块:

function Test-FtpDirectory { [CmdletBinding()] param( [Parameter(Mandatory)] [string]$Uri, [Parameter(Mandatory)] [string]$Username, [Parameter(Mandatory)] [string]$Password, [Parameter(Mandatory)] [string]$Directory ) # 构建完整FTP URI(注意:.NET要求URI以/结尾表示目录) $fullUri = "$Uri$Directory/" Write-Verbose "Checking directory: $fullUri" try { # 创建FTP请求 $request = [System.Net.FtpWebRequest]::Create($fullUri) $request.Credentials = New-Object System.Net.NetworkCredential($Username, $Password) $request.Method = [System.Net.WebRequestMethods+Ftp]::ListDirectory $request.Timeout = 10000 # 10秒超时 # 发送请求并获取响应 $response = $request.GetResponse() $response.Close() Write-Output "Directory exists: $Directory" return $true } catch [System.Net.WebException] { $statusCode = $_.Exception.Response.StatusCode if ($statusCode -eq "ActionNotTaken") { # 550错误对应ActionNotTaken Write-Output "Directory does not exist: $Directory" return $false } else { Write-Warning "FTP error: $statusCode - $($_.Exception.Message)" return $false } } catch { Write-Warning "Unexpected error: $($_.Exception.Message)" return $false } } # 使用示例 Test-FtpDirectory -Uri "ftp://ftp.example.com/" -Username "user" -Password "pass" -Directory "/backup/2024"

实操心得:

  • .NET FtpWebRequest对目录URI要求严格:必须以/结尾,否则会被视为文件;
  • ListDirectory方法比GetFileSize更可靠,因后者对目录返回550,但某些服务端对空目录也返回550;
  • Windows Server 2012+默认启用TLS 1.2,若FTP服务端仅支持SSL 3.0,需在脚本开头添加[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12。

4. 生产环境避坑指南:那些文档里不会写的血泪教训

4.1 路径编码陷阱:中文、空格、特殊字符如何安全传递

FTP协议本身不定义字符编码,服务端实现五花八门。我们曾在一个政府项目中遇到:/数据报表/2024年Q1/在vsftpd上正常,但在某国产NAS上cwd()始终返回550。抓包发现,NAS将路径按GBK编码后传输,而客户端用UTF-8发送。解决方案分三层:

  1. 客户端预处理:对路径进行URL编码(非百分号编码,而是FTP专用的%xx转义):
    from urllib.parse import quote safe_dir = quote(directory, safe='/') # 仅对非路径分隔符编码
  2. 服务端配置:在vsftpd.conf中添加utf8_filesystem=YES,强制使用UTF-8;
  3. 降级策略:当cwd()失败时,尝试用latin-1编码重试(覆盖大部分西欧字符)。

提示:永远不要在路径中使用* ? [ ]等shell通配符,FTP服务器不解析它们,但客户端shell可能提前展开导致路径错误。

4.2 超时与重试策略:如何避免“假阴性”误判

网络抖动、服务端负载高、防火墙策略变更都可能导致单次CWD失败。我们的重试策略如下:

  • 首次尝试:10秒超时,不重试;
  • 失败后:等待1秒,用相同参数重试1次;
  • 仍失败:记录WARN日志,返回False,但不中断主流程;
  • 关键路径(如部署根目录):增加第三次重试,超时设为15秒。
# 在ftp_directory_exists函数中插入重试逻辑 for attempt in range(3): try: # 执行CWD操作 ftp.cwd(clean_dir) return True, f"Success on attempt {attempt+1}" except ftplib.error_perm as e: if attempt == 2: # 最后一次尝试 raise time.sleep(1) continue

4.3 权限边界问题:如何区分“不存在”和“无权限”

这是运维中最易混淆的场景。550错误码既可能表示路径不存在,也可能表示用户无访问权限。我们的鉴别方法是双路径交叉验证:

  1. 先检查一个已知存在的父目录(如/或/pub)是否可访问;
  2. 再检查目标目录;
  3. 若父目录成功而目标目录失败,则大概率是“无权限”;
  4. 若父目录也失败,则可能是服务端宕机或认证失败。
# 在主函数中添加 parent_dir = "/".join(clean_dir.split("/")[:-1]) or "/" if not ftp_directory_exists(..., directory=parent_dir)[0]: return False, f"Parent directory inaccessible: {parent_dir} (check auth or server status)"

4.4 连接池与并发安全:批量检查时的性能瓶颈

当需要检查数百个目录时,逐个建立FTP连接会导致性能雪崩。我们的解决方案是:

  • 复用连接:单次FTP会话中连续执行多次cwd(),避免反复connect/login/quit;
  • 连接池管理:使用ftplib.FTP实例缓存,配合threading.local()实现线程安全;
  • 并发控制:限制最大并发连接数为3(FTP服务端通常限制每IP连接数为2~5)。
import threading _local = threading.local() def get_ftp_client(): if not hasattr(_local, 'ftp'): _local.ftp = ftplib.FTP() _local.ftp.connect(host, port, timeout=10) _local.ftp.login(user, passwd) return _local.ftp

5. 常见问题速查表与排查技巧实录

我们整理了过去三年中客户反馈最集中的12个问题,按发生频率排序,并附上现场排查步骤:

问题现象可能原因排查步骤解决方案
530 Login incorrect持续出现用户名密码含特殊字符未转义1. 用echo "user:pass" | base64验证凭据
2. 抓包看AUTH命令是否被截断
URL编码密码:quote(password, safe='')
500 Illegal PORT command客户端NAT环境不支持主动模式1.ftp.set_pasv(True)强制被动模式
2. 检查服务端PASV端口范围是否开放
在防火墙放行PASV端口段(如50000-51000)
550 Can't change directory to /xxx但目录明明存在路径含Unicode字符且编码不匹配1.ftp.sendcmd('OPTS UTF8 ON')开启UTF8
2. 用ftp.encoding='utf-8'
服务端配置utf8_filesystem=YES
脚本在Docker中运行超时Alpine Linux缺少glibc依赖1.apk add --no-cache ca-certificates
2.apk add --no-cache openssl
改用debian-slim基础镜像或安装缺失库
226 Transfer complete但实际没列出内容LIST命令被服务端禁用1.ftp.sendcmd('HELP')查看支持命令
2. 尝试NLST替代
改用CWD+PWD方案(不依赖LIST)
553 Could not create file误判为目录不存在混淆了文件创建与目录切换命令1. 检查代码是否误用storbinary()
2. 确认调用的是cwd()而非stor()
严格区分cwd()(目录)与stor()(文件)
425 Can't open data connection服务端PASV模式配置错误1.ftp.sendcmd('PASV')看返回IP是否为内网地址
2. 用telnet ip port测试数据端口
服务端配置pasv_address=公网IP
501 Invalid parameter在长路径上服务端路径长度限制(如IIS FTP限260字符)1.len(directory)检查路径长度
2. 用ftp.sendcmd('PWD')确认当前路径
缩短目录名或使用相对路径
534 Security violation服务端强制FTPS但客户端未启用SSL1.ftp = FTP_TLS()替代FTP()
2.ftp.auth('TLS')
启用显式TLS:ftp.prot_p()
550 Permission denied但用户有读权限SELinux或AppArmor限制FTP进程1.getenforce检查SELinux状态
2.ausearch -m avc -ts recent查拒绝日志
setsebool -P ftpd_full_access on
500 Unknown command对OPTS UTF8服务端不支持UTF8扩展1.ftp.sendcmd('FEAT')查看功能列表
2. 若无UTF8则改用latin-1
降级编码并URL编码路径
550 Failed to change directory在根目录服务端chroot配置导致根目录不可写1.ftp.sendcmd('PWD')确认初始路径
2. 尝试cd ..看是否允许
联系管理员调整chroot设置

独家排查技巧:

  • 抓包黄金组合:在客户端执行tcpdump -i any port 21 -w ftp.pcap,用Wireshark打开,过滤ftp.request.command == "CWD",直接看服务端返回的原始响应码和文本;
  • 服务端日志定位:vsftpd日志在/var/log/vsftpd.log,搜索CWD关键字,看是否有FAIL标记;
  • 最小化复现:用lftp -d开启调试模式,它会打印每条命令的发送与接收,比任何文档都真实。

6. 扩展思考:当FTP不再是唯一选择时的技术演进

虽然本篇聚焦FTP,但必须坦诚:在2024年的技术栈中,纯FTP正快速被更安全、更高效的协议替代。我们在某金融项目中完成了平滑迁移,经验值得分享:

  • SFTP替代FTP:OpenSSH自带SFTP服务,paramiko库的SFTPClient.listdir_attr()可直接返回目录列表,stat()方法能精确判断存在性,且全程加密;
  • WebDAV作为中间层:Nginx配置dav_methods后,用requests库发送HEAD请求即可判断路径存在(response.status_code == 200);
  • 对象存储网关:MinIO或Cloudflare R2提供S3兼容API,head_object()比FTP的CWD快10倍且100%可靠。

但这不意味着FTP该被淘汰。大量工业设备、医疗仪器、老式POS终端仍只支持FTP。我们的策略是:新项目用S3/WebDAV,遗留系统用FTP+本文方案加固。技术选型不是非此即彼,而是让工具匹配场景。

最后分享一个小技巧:在所有FTP脚本开头加入一行echo "[INFO] $(date): Starting FTP check for $DIRECTORY",当凌晨三点告警响起时,这行日志能帮你节省47分钟排查时间——因为你知道,问题不在脚本逻辑,而在那个突然被防火墙策略封禁的FTP端口。

相关新闻

FTP判断目录是否存在:四种方案实测与生产级避坑指南

FTP判断目录是否存在:四种方案实测与生产级避坑指南

1. 项目概述:为什么一个“目录是否存在”的判断,值得单独拿出来深挖?FTP协议本身没有原生的test -d或ls -d这类原子化存在性校验命令——它不像现代API那样返回明确的HTTP 200/404状态码,也不像本地文件系统能直接调用os.path.isd…

2026/10/20 4:21:38 阅读更多 →
逆向分析入门:从x64dbg调试到Ghidra反编译实战

逆向分析入门:从x64dbg调试到Ghidra反编译实战

1. 这不是“破解游戏”的速成课,而是逆向分析的第一次真实触感很多人看到“逆向分析”四个字,第一反应是:黑进系统、绕过授权、改游戏金币——这其实是把手术刀当菜刀用。我带过十几期网安实践课,每期开课前都会让学员先拆一个最基…

2026/10/20 4:21:38 阅读更多 →
格式工厂v2.70绿色版:本地免费批量视频转换与参数设置指南

格式工厂v2.70绿色版:本地免费批量视频转换与参数设置指南

简介:格式工厂 v2.70 绿色版是一款面向多媒体格式转换需求的轻量工具,支持常见音频、视频、图片格式互转,适合需要快速批量处理文件的普通用户和办公场景。此版在 XP 环境下完成功能测试,并针对原版界面与联网行为做了精简处理&am…

2026/10/20 4:21:38 阅读更多 →

最新新闻

artcraft类创作工具技术架构与交互设计实战指南

artcraft类创作工具技术架构与交互设计实战指南

1. 从"artcraft"这个名字说起:一个被低估的创作工具定位问题第一次看到"artcraft"这个词,我脑子里蹦出来的第一反应是"艺术"加"手艺"的组合。这不是一个随便拼出来的名字,它暗示了一种很具体的产品气…

2026/10/20 6:27:33 阅读更多 →
从自由发挥到受控执行:大模型Skill机制实战

从自由发挥到受控执行:大模型Skill机制实战

1. 先弄明白:Skill到底解决的是什么问题1.1 大模型能力的边界在哪里如果你用过几款主流的大模型对话工具,就会发现一个奇怪的现象:让模型帮你"解释一段代码""写个正则表达式"很容易,但让它"按团队规范自…

2026/10/20 6:27:33 阅读更多 →
JavaFX+SSM架构实战:桌面客户端与数据服务端的高效整合

JavaFX+SSM架构实战:桌面客户端与数据服务端的高效整合

简介:这是一份融合 JavaFX 与 SSM 框架的 ERP 系统完整项目,面向需要将桌面 GUI 与企业级后端整合开发的 Java 学习者、毕业设计或项目实战人群,既能学习界面设计,也能掌握经典后端框架的落地方式。资源共包含 2 个文件&#xff1…

2026/10/20 6:27:33 阅读更多 →
Python与API文本分析实战:从文本清洗到工程化部署

Python与API文本分析实战:从文本清洗到工程化部署

AI应用的潜力,有一大半藏在文本里。文本分析这个方向,我自己前前后后折腾过不少方案,从早期的正则规则、词频统计,到开源模型微调,再到现在用 Python 接各类大模型 API 做文本分析,最大的感受是&#xff1a…

2026/10/20 6:27:33 阅读更多 →
IPv4报文头部详解:字段、分片与网络排查核心知识

IPv4报文头部详解:字段、分片与网络排查核心知识

做网络排查做得久了,你会发现一个特别有意思的现象:很多人能把TCP的三次握手、四次挥手讲得天花乱坠,可一旦你把抓包工具里的一帧数据展开,让他逐字节解释一下IPv4头部,他反而会卡壳。TCP、UDP这些传输层协议太出名&am…

2026/10/20 6:27:33 阅读更多 →
STM32 bxCAN实战:从物理层到过滤器配置与调试排障

STM32 bxCAN实战:从物理层到过滤器配置与调试排障

做嵌入式这几年,UART、I2C、SPI都是老朋友,但真正让我觉得“像个通信工程师”的,是开始啃STM32的CAN外设之后。原因很简单:在汽车、机器人和工业现场,CAN总线是默认的“老大哥”,而它在微控制器上的硬件实现…

2026/10/20 6:26:33 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →