news 2026/10/8 2:35:43

PowerShell脚本统计文件夹大小:快速揪出磁盘空间占用大户

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PowerShell脚本统计文件夹大小:快速揪出磁盘空间占用大户

C 盘飘红大概是每个用 Windows 的人都会遇到的日常,更烦的是想知道“到底哪个文件夹占了空间”,往往只能一层层打开资源管理器,右键点属性,看几秒进度条再点下一层。装 TreeSize、WinDirStat 这类工具确实方便,但在公司环境里要申请安装权限,流程走完耐心也没了。后来我养成了一个习惯:直接跑一段 Windows 脚本,把指定路径下所有直接文件/文件夹的大小一次性列出来,按大到小排序,几秒钟心里就有数。这篇就把我从第一版踩坑到最终可复用脚本的完整过程写出来,适合系统运维、开发同学,也适合只想把磁盘空间搞清楚的家用用户。

1. 需求拆解:先搞清楚“所有直接文件/文件夹的大小”到底算什么

1.1 关键词里的“直接”二字

标题里的“直接”很容易被忽略,但恰恰决定了脚本怎么写。所谓“指定路径下所有直接文件/文件夹”,意思是只看路径下的第一层子项:假设指定D:\Data,脚本要列出D:\Data下面每一个子目录和每一个文件,而不用把子目录里的三级四级内容单独列出来。

这里有个很容易想当然的误区:结构上只看一层,但大小计算上必须递归到底。一个文件夹的“大小”,显然是把它里面所有文件、所有嵌套子目录里的文件全部加起来。只统计第一层文件的大小,忽略子目录里的内容,那结果毫无意义。我在第一版脚本里就踩过这个坑,每个文件夹算出来都是 0,因为DirectoryInfo对象本身没有Length属性。

所以需求可以拆成两层:

  • 遍历层面:枚举指定路径的直接子项,不继续列子目录内部的直接子项。
  • 统计层面:文件直接拿Length,文件夹要递归累加里面所有文件的大小。

1.2 典型使用场景

这种脚本在实际工作中非常高频,至少这几类场景我全遇到过:

  • 磁盘告警:某台服务器 C 盘空间不足,登录上去先跑一遍脚本,看哪个目录占用最大。
  • 备份前评估:要迁移数据或做项目预算,需要快速比较几个目录的量级。
  • 用户目录配额:多人共用一台机器,扫一遍每个用户目录的大小。
  • 日志清理:日志目录特别大,脚本排序后直接定位到最大的日志子目录,再针对性做清理策略。

这种场景的共同特点是:不需要精确到每一个字节,但需要尽快分清主次。先列 Top 20,把大头找出来,后续再针对可疑目录精细排查。

1.3 为什么不自带工具,反而要写脚本

Windows 自带功能不是不能用,而是不适合批量操作。右键属性只能看单个文件夹;磁盘管理的“存储感知”面向整个磁盘,不会按你的指定路径一层层列出来;“磁盘清理”更是只针对系统缓存体系,用户很难把它当目录分析器用。

第三方分析工具功能强大,但至少有三个现实阻力:需要安装权限,公司环境常常不允许;图形界面在远程服务器上体验很差;工具本身有学习成本和后台服务驻留。脚本的好处是零依赖,Windows 自带的 PowerShell 5.1 就能跑,把.ps1文件拷过去直接执行,用完即走,特别适合批量交付给运维团队共用。

2. 方案选型:cmd 批处理有几个硬伤,PowerShell 才是合适底座

2.1 批处理不是不能写,但容易写到一半怀疑人生

看到“Windows 脚本”,很多人第一反应是写.bat。我早年也这么干过,但认真写完一个像样的目录统计脚本后,就彻底放弃用纯批处理做这类事了。三个硬伤绕不开:

第一,set /a只支持 32 位整数运算。文件大小超过 2GB 就可能溢出,而现代硬盘上一个视频文件动辄几个 GB,累加几个大文件直接算出负数,这结果没人敢信。

第二,递归逻辑非常别扭。批处理没有一个干净的“遍历目录返回集合”的抽象,靠for /r嵌套和dir /s搭配文本解析,代码绕来绕去,可读性极差。举个例子:

@echo off setlocal enabledelayedexpansion set "target=%~1" for /d %%d in ("%target%\*") do ( set "size=0" for /r "%%d" %%f in (*) do ( set /a "size+=%%~zf" ) echo %%d !size! )

这段批处理看着能跑,实际上一堆问题:空文件取不到%~zf时可能把变量置空、2GB 以上溢出、文件名带空格或特殊字符时解析错乱、显示结果的分隔符还要自己拼。用批处理解决这个问题,是在跟语言本身的短板较劲。

第三,本地化输出不稳定。dir /s的汇总行在中文系统显示“个文件”,英文系统显示File(s),用findstr提取数量时还得区分语言版本,换一台系统脚本就失效。

2.2 PowerShell 的优势恰好补上这些短板

同样是系统自带脚本环境,Windows PowerShell 5.1 从 Win7/Win2008 R2 开始就一直内置,完全不需要额外安装。它更适合这个任务:

  • 原生 64 位整数[long],算 TB 级别也不溢出。
  • Get-ChildItem支持递归枚举,返回结构化对象,可以直接拿Length、Attributes、FullName。
  • Measure-Object -Property Length -Sum一行完成求和。
  • 结果可以统一输出为对象,后续要排序、格式化、导出 CSV 都非常方便。

这几点不是锦上添花,而是决定了脚本能写得多稳。尤其是对象管道模型,让每一步操作都清晰可见:取数据、计算、排序、格式化各管一段,调试时在任意步骤一截就能看到中间结果。这和批处理里满屏字符串解析完全是两种开发体验。

3. 脚本落地:从一条管道命令到带参数的 Get-DirectSize.ps1

3.1 第一版:一条命令先探路,文件夹全是 0

刚接到这个需求时,我先用一条 PowerShell 管道命令试水:

Get-ChildItem -Path "D:\Data" -Force | ForEach-Object { if ($_.PSIsContainer) { [PSCustomObject]@{ Name = $_.Name; Size = 0 } } else { [PSCustomObject]@{ Name = $_.Name; Size = $_.Length } } } | Sort-Object Size -Descending | Format-Table -AutoSize

结果文件的大小正常,所有文件夹的大小都是 0。这个结果直观暴露了问题:文件夹的大小必须递归计算。于是进入第二版。

3.2 第二版:递归函数计算目录总大小

递归函数的思路很直接:进入一个目录,遍历它的直接子项;遇到文件就累加Length,遇到子目录就调用函数本身,再把返回值累加进总大小。代码如下:

function Get-DirSize { param([string]$DirPath) $total = 0L try { $items = Get-ChildItem -LiteralPath $DirPath -Force -ErrorAction Stop foreach ($item in $items) { if ($item.PSIsContainer) { # 跳过符号链接和目录联接,避免重复计算和死循环 $isLink = $item.Attributes -band [System.IO.FileAttributes]::ReparsePoint if (-not $isLink) { $total += Get-DirSize -DirPath $item.FullName } } else { $total += $item.Length } } } catch { Write-Warning "无法访问目录: $DirPath - $($_.Exception.Message)" } return $total }

这段函数有几个关键点值得展开。

-ErrorAction Stop配合try/catch,是为了让权限受限的目录能暴露出来。如果不加 Stop,错误会一直被静默吞掉,脚本跑完你根本不知道哪些目录没统计进去,结果偏小还不自知。加上 Stop 之后,每个无法访问的目录都会打印一条警告,最终结果里哪些部分可信、哪些部分缺失,一目了然。

-Force参数也很重要。它让Get-ChildItem包含隐藏文件和系统文件。如果不加,用户目录里常见的AppData这类隐藏目录直接不会被枚举,统计结果会严重偏低。

判定符号链接的那一行是实践里总结出来的:$item.Attributes -band [System.IO.FileAttributes]::ReparsePoint。文件夹大小统计最怕的就是遇到 junction 或符号链接指向自己所在的目录树,递归会无限循环。跳过这类链接,只统计物理存在的真实目录,结果才可靠。

3.3 第三版:单次遍历分组,大目录下的性能优化

递归函数版逻辑准确,但有一个性能问题:每进入一个子目录就要调用一次Get-ChildItem,目录层级深、子目录多的时候,系统调用开销很大。

如果只是需要“指定路径下每个直接子项的大小排行”,还有一条更快的路:一次性递归枚举路径下的所有文件,按它们在顶层的归属分组,再对每组求和。代码如下:

$target = (Resolve-Path -LiteralPath "D:\Data").Path.TrimEnd('\') Get-ChildItem -LiteralPath $target -Recurse -File -Force -ErrorAction SilentlyContinue | Group-Object { $rel = $_.FullName.Substring($target.Length).TrimStart('\') $rel.Split('\')[0] } | ForEach-Object { $first = $_.Group | Select-Object -First 1 $rel = $first.FullName.Substring($target.Length).TrimStart('\') $isDirectFile = (-not $first.PSIsContainer) -and ($rel -notmatch '\\') [PSCustomObject]@{ Name = $_.Name Type = if ($isDirectFile) { "文件" } else { "文件夹" } Size = ($_.Group | Measure-Object -Property Length -Sum).Sum } } | Sort-Object Size -Descending | Format-Table -AutoSize

原理解释一下:每个文件的FullName去掉目标路径前缀后,取第一段路径作为分组键。D:\Data\sub1\1.txt这样的文件,相对路径是sub1\1.txt,第一段是sub1,就和sub1目录下所有文件分到同一组。D:\Data\readme.txt的相对路径没有反斜杠,第一段就是文件名本身,所以每个直接文件单独成组,同时也被识别成“文件”类型。

这个方案比递归函数版快得多:整棵树只枚举一次文件,不反复创建目录枚举对象,也不递归调用函数。代价是空文件夹不会出现在结果里——这通常不影响使用,因为你关注的是“谁占了空间”,空文件夹本来就占不了空间。

3.4 整合成正式脚本:Get-DirectSize.ps1

把两种策略整合到一个脚本里,默认用递归函数版保证准确,加-Fast参数切换到分组优化版,另外支持设置显示条数、导出 CSV。完整源码如下:

param( [string]$Path = ".", [int]$Top = 20, [switch]$Fast, [switch]$ExportCsv ) function Format-Size { param([long]$Bytes) if ($Bytes -lt 1KB) { return "$Bytes B" } if ($Bytes -lt 1MB) { return "{0:N2} KB" -f ($Bytes / 1KB) } if ($Bytes -lt 1GB) { return "{0:N2} MB" -f ($Bytes / 1MB) } if ($Bytes -lt 1TB) { return "{0:N2} GB" -f ($Bytes / 1TB) } return "{0:N2} TB" -f ($Bytes / 1TB) } function Get-DirSize { param([string]$DirPath) $total = 0L try { $items = Get-ChildItem -LiteralPath $DirPath -Force -ErrorAction Stop foreach ($item in $items) { if ($item.PSIsContainer) { $isLink = $item.Attributes -band [System.IO.FileAttributes]::ReparsePoint if (-not $isLink) { $total += Get-DirSize -DirPath $item.FullName } } else { $total += $item.Length } } } catch { Write-Warning "无法访问目录: $DirPath - $($_.Exception.Message)" } return $total } if (-not (Test-Path -LiteralPath $Path)) { Write-Host "路径不存在: $Path" exit 1 } if (Test-Path -LiteralPath $Path -PathType Leaf) { Write-Host "这是文件路径,请传入目录路径。" exit 1 } $target = (Resolve-Path -LiteralPath $Path).Path.TrimEnd('\') $results = @() if ($Fast) { $results = Get-ChildItem -LiteralPath $target -Recurse -Force -ErrorAction SilentlyContinue | Group-Object { $rel = $_.FullName.Substring($target.Length).TrimStart('\') $rel.Split('\')[0] } | ForEach-Object { $first = $_.Group | Select-Object -First 1 $rel = $first.FullName.Substring($target.Length).TrimStart('\') $isDirectFile = (-not $first.PSIsContainer) -and ($rel -notmatch '\\') [PSCustomObject]@{ Name = $_.Name Type = if ($isDirectFile) { "文件" } else { "文件夹" } Size = ($_.Group | Measure-Object -Property Length -Sum).Sum } } } else { foreach ($item in (Get-ChildItem -LiteralPath $target -Force -ErrorAction SilentlyContinue)) { if ($item.PSIsContainer) { $results += [PSCustomObject]@{ Name = $item.Name Type = "文件夹" Size = Get-DirSize -DirPath $item.FullName } } else { $results += [PSCustomObject]@{ Name = $item.Name Type = "文件" Size = $item.Length } } } } if ($ExportCsv) { $results | Sort-Object Size -Descending | Export-Csv -Path "DirectSize-$(Get-Date -Format 'yyyyMMddHHmmss').csv" -NoTypeInformation -Encoding UTF8 } $results | Sort-Object Size -Descending | Select-Object -First $Top | ForEach-Object { [PSCustomObject]@{ 名称 = $_.Name 类型 = $_.Type 大小 = Format-Size -Bytes $_.Size 字节 = $_.Size } } | Format-Table -AutoSize

这段脚本里有几个细节是我实际打磨过的。

先校验路径是否存在,再分辨是文件还是目录。很多人输入的路径是复制过来的,末尾可能带一个看不见的空格或者引号,Test-Path会在第一时间拦住,避免后面报错。传入文件路径时直接提示“请传入目录路径”,也比让Resolve-Path抛一个突兀的异常友好得多。

统一在最后用Format-Size做单位换算。之前我试过直接在对象里存格式化的字符串,结果导出 CSV 时只能拿到“1.23 GB”这种文本,后续要做数值排序非常麻烦。正确做法是对象里保留原始字节数Size,显示层做格式化,导出 CSV 也保留原始数值。

4. 运行方式与常见报错:执行策略、中文乱码、路径带特殊字符

4.1 推荐运行姿势

脚本保存为Get-DirectSize.ps1后,最简单的运行方式是打开 PowerShell 窗口,切到脚本所在目录,然后执行:

.\Get-DirectSize.ps1 -Path "D:\Data" -Top 10

如果需要规避系统执行策略限制,用-ExecutionPolicy Bypass临时放行,只对当前进程生效,不修改系统全局配置:

powershell -NoProfile -ExecutionPolicy Bypass -File "C:\scripts\Get-DirectSize.ps1" -Path "D:\Data" -Top 10

在 cmd 或双击bat时也推荐用这个姿势。-NoProfile是为了不加载用户配置,避免某些机器上的自定义函数或别名干扰执行。

4.2 报错:无法加载 ps1,因为在此系统上禁止运行脚本

这恐怕是新手遇到最多的报错,本质是执行策略默认 Restricted。我之前说过用命令行的-ExecutionPolicy Bypass绕过,如果想在当前用户级别放开,也可以执行:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

RemoteSigned意味着本地脚本可以运行,从网络下载的脚本必须有数字签名,比完全放开安全得多。日常使用这个设置就够了,不建议用Unrestricted。

4.3 中文乱码问题

脚本里混用了中文提示和列名,如果编辑器把文件保存为无 BOM 的 UTF-8,Windows PowerShell 5.1 有可能把中文字符解读成乱码,直接导致脚本语法错误或者输出乱码。

解决办法有两个:一是用 VS Code 保存文件时选择“UTF-8 with BOM”编码;二是脚本内不加中文,全部用英文。考虑到最终用户还是希望看到中文输出,我建议第一种。PowerShell 7 以后对无 BOM UTF-8 的支持好了很多,但在老系统上跑 5.1 时,依然推荐带 BOM。

4.4 路径带方括号和空格

路径里的空格其实还好,PowerShell 的引号能处理。真正容易出问题的是方括号,比如D:\data[2024]\log。Get-ChildItem -Path默认把方括号当通配符处理,路径就找不到了。脚本里统一用了-LiteralPath,就是为这个问题留的后门。如果你想手动敲命令,也建议全程用-LiteralPath。

4.5 结果偏小,但没有报错

还有一种隐蔽问题:脚本跑完没报错,但结果明显偏小。常见原因有三个,隐藏目录没算进去、符号链接被跳过、权限不足的目录被SilentlyContinue吞掉了。递归函数版遇到权限问题会打印警告,所以默认模式下结果可信度更高;-Fast模式为了性能用了SilentlyContinue,看到可疑结果时,建议切回默认模式,看警告信息。

5. 边界情况踩坑实录:权限拒绝、符号链接、隐藏文件

5.1 权限拒绝:宁可警告,不要静默

Windows 文件系统里总有那么几个目录当前用户没有读权限,比如系统卷信息目录、其他用户的配置文件目录。你用一个普通用户身份跑脚本,这些目录会报UnauthorizedAccessException。

很多教程喜欢在Get-ChildItem后面挂-ErrorAction SilentlyContinue,图省事把错误全部吞掉。我强烈不建议在默认模式这么干。正确的做法是让脚本打印警告,告诉你哪个目录没读到。这样你至少能判断:如果只少一个无关紧要的目录,结果可以接受;如果少的是要重点分析的目录,你会立刻意识到需要换更高权限的身份执行,而不是对着一个偏小的结果做错误判断。

实战里我遇到过一种情况:同一个目录,用普通权限跑出来 20GB,用管理员权限跑出来 60GB,差距大得吓人。原因就是普通权限没进到几个子目录里。所以权限问题不只是一个报错处理问题,它直接决定了统计结果能不能用。

5.2 符号链接和目录联接:防止重复计算和死循环

Windows 下的符号链接和目录联接(junction)是隐藏很深的坑。典型场景是 C 盘用户目录里某些文件夹被重定向到 D 盘,或者网盘同步目录建了链接指向本地其他位置。如果不做处理,脚本可能遇到两种问题:

  • 链接指向的目录在目标路径之外,结果里重复计入不该算的空间。
  • 链接指向父目录或自身形成环,递归无限循环,脚本卡死。

我在递归函数里通过ReparsePoint属性判断并跳过所有链接,这是最稳妥的做法。代价是链接指向的目标内容不会被统计,但这类内容在物理上往往不属于当前目录树,跳过反而更符合“计算该路径下目录大小”的语义。

这里也解释一下为什么-Fast模式没有显式跳过链接。Get-ChildItem -Recurse对链接目录的跟随行为在不同系统版本上有差异,万一遇到特殊目录,用-Fast跑出来的结果可能会包含链接内容。所以涉及链接较多的目录,默认模式的结果优先级更高。

5.3 隐藏文件和系统文件:不加 -Force 等于白跑

Windows 资源管理器里,隐藏文件和系统文件默认是不显示的。很多人统计目录大小时继承了这种“视觉盲区”,脚本也没加-Force,结果把一个 200GB 的目录统计成 80GB。

最典型的例子就是用户目录下的AppData:它默认隐藏,却常常是整个用户目录里最大的部分。脚本里的Get-ChildItem统一加了-Force,就是强迫自己不要忽略这类目录。统计磁盘占用时,物理文件只要存在于磁盘上,不管隐藏属性如何,都应该算进去。

5.4 空文件夹和空文件:不显示的意外

-Fast模式因为基于“文件分组”,空文件夹不会出现在结果里。这在大多数场景下合理,但也有例外:有人想确认目录结构里到底有多少空文件夹,用来做清理参考。这种需求就得回到默认模式,因为它是枚举直接子项,空文件夹也会被列出来并把大小计为 0。

另一个小细节是 0 字节文件。这些文件会正常出现在结果里,大小显示为 0 B,排序后通常会沉到底部。如果想清理大量小文件,建议保留这些结果,数量积少成多也值得关注。

6. 性能优化与右键菜单扩展:大目录下的实测经验和进阶玩法

6.1 慢的根源:重复枚举成了性能瓶颈

我在一个文件数量超过 30 万的目录上试过递归函数版,完整跑完要等很久。分析下来瓶颈很明确:每个子目录都要重新调用一次Get-ChildItem,几十万文件分布在几万个目录里,就会产生几万次系统枚举调用,大部分时间花在创建枚举对象、排序目录项、解析元数据上。

针对这类场景,两个原则很重要:

  • 尽量把-Path缩小到目标子目录。比如你知道是某个项目目录很大,就不要从整个盘符开始扫,先把范围缩小一圈。
  • 关注数量级,而不是精确字节。使用-Fast模式拿到 Top 排序,定位到最有嫌疑的几个目录后,再单独用默认模式细算。这个组合拳比任何参数调优都有效。

6.2 -Fast 模式为什么快:单次遍历与流式处理

-Fast模式的核心是一次性递归枚举所有文件,然后按顶层归属分组汇总。相比递归函数版,它少了反复创建目录枚举对象的开销,而且整个管道是流式的,文件被枚举出来后马上进入分组阶段,内存压力也小。实测在同样的目录上,-Fast模式快一个数量级也不夸张。

代价前面说过:空文件夹不显示,链接目录可能被跟随。所以我的建议是:日常快速判断用-Fast,严谨统计用默认模式,两者互补而不是替代。

6.3 用 Robocopy 核对目录总大小

如果你需要验证整个路径的总大小是否准确,可以用系统自带的 Robocopy 做交叉核对。Robocopy 的/L参数表示只列出不真正复制,输出里会给出文件大小汇总:

robocopy "D:\Data" NULL /L /S /BYTES /XJ /NFL /NDL /NJH /NJS

其中/BYTES让输出使用纯字节,/XJ排除 junction 点,/NFL和/NDL不显示每个文件和目录,/NJH和/NJS不显示作业头和摘要,最终只留汇总信息。这个方法用来验证脚本结果是否在一个合理范围内很实用,尤其是刚部署脚本时,我会先用它做一次交叉验证,确认脚本没有系统性漏算。

6.4 右键菜单扩展:在文件夹上直接运行

脚本好不好用,很大程度上取决于调用是否方便。我后期把脚本注册到了资源管理器右键菜单,在任意文件夹上点右键,选择“计算文件夹大小”,脚本就会自动以该目录为-Path执行。

注册表操作如下,保存为.reg文件导入即可:

Windows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\Directory\shell\SizeCalc] @="计算文件夹大小" [HKEY_CLASSES_ROOT\Directory\shell\SizeCalc\command] @="powershell -NoProfile -ExecutionPolicy Bypass -File \"C:\\scripts\\Get-DirectSize.ps1\" -Path \"%V\""

注意.reg文件里的双引号和反斜杠都要转义,路径里的\\scripts\\是注册表格式的要求。导入后右键文件夹即可看到菜单项。如果不想要了,删除注册表里对应的SizeCalc键即可。

6.5 配合清理脚本做自动化

脚本还有一个进阶用法:接入定时任务。比如每周跑一次,把结果导出 CSV,再对超过某个阈值的目录执行归档或清理。我这边接过一个实际需求:日志目录超过 10GB 自动删除 7 天前的旧日志。实现思路就是在ExportCsv输出的基础上,再加一段按日期过滤并执行删除的逻辑,统计分析让Get-DirectSize.ps1完成,清理动作单独写脚本,职责清晰,出问题时也好排查。

自动化场景下更推荐使用默认模式,因为它对权限问题有明确警告,不会在静默状态下做出错误的清理决策。定时任务里执行时,建议统一用-ExecutionPolicy Bypass的完整命令,避免任务计划程序的执行环境策略差异导致脚本跑不起来。

最后说点大实话

这个脚本我在自己工作机上至少用了半年,最大的收获不是那几行代码,而是“分层排查”的思路:先用快模式排序定位嫌疑目录,再对重点目录用慢而准的模式细算,中间穿插权限检查和符号链接判断。很多看起来“玄学”的占用异常,最后都是某个隐藏目录或者链接目录在作怪,脚本里显式处理这些边界,比出了问题再猜要省心得多。如果你第一次跑脚本就发现某个目录大得离谱,先别急着下结论,重点看一下它的子目录里有没有指向其他盘的 junction,再用管理员身份跑一遍对比结果。祝你的 C 盘永远有空间。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 2:35:38

Pandas实战:从数据清洗到可视化的完整分析流程

干了十来年数据相关的工作,我几乎每天都要跟Pandas打交道。每次有人问我“数据分析到底从哪里开始”,我的答案从来没变过:先把Pandas玩熟。这句话听起来有点老生常谈,但真正接手过脏乱差业务数据的人都明白,数据清洗、…

作者头像 李华
网站建设 2026/10/8 2:35:31

IEEE 1588-2019 深度解析:PTP 对时原理、Profile 配置与实战避坑指南

简介:IEEE Std 1588-2019 是 IEEE 仪器与测量学会 TC-9 制定的网络测量与控制系统精确时钟同步协议标准,作为 2008 版的修订版本,面向从事电力系统、通信网络、自动化与交通管理等需要高精度时间同步的工程师与研究人员。标准定义了主时钟、边…

作者头像 李华
网站建设 2026/10/8 2:35:08

AI辅助论文写作:使用边界、学术诚信与声明撰写实操指南

最近我在帮几位青年教师看论文初稿,发现一个特别有意思的现象:不管是本科生毕业论文还是研究生小论文,致谢部分或者文末声明里,越来越多出现“本文使用了XX AI辅助润色”“部分段落由AI生成,已人工核验”这类表述。有的…

作者头像 李华
网站建设 2026/10/8 2:34:52

Linux内核模块GPL符号限制解析:从Unknown symbol到桥接方案

内核模块开发最容易被新手踩到的坑,就是加载一个 .ko 时撞上 GPL-only 符号。上周一个合作厂商的闭源驱动在我内核上一加载就报了一串 Unknown symbol,dmesg 里跟着 GPL-only 相关的提示,最后不得不帮他们做了一层符号桥接才跑通。今天借这个…

作者头像 李华
网站建设 2026/10/8 2:34:16

Linux PTP高精度时间同步实战:从NTP痛点硬件时间戳到部署排查

做运维这些年,最容易被忽视又最要命的问题就是时间不同步。记得有一次线上数据库集群因为主从时间偏差超过几百毫秒,直接触发脑裂保护,整整折腾了一宿,最后排查发现是NTP在大流量下的精度根本撑不住。后来换了Linux PTP&#xff0…

作者头像 李华
网站建设 2026/10/8 2:34:16

Selenium爬虫实战:攻破JavaScript渲染动态页面的核心技巧

写爬虫最怕遇到什么&#xff1f;不是反爬策略有多变态&#xff0c;而是你用requests把页面源码拉回来&#xff0c;发现它和你浏览器里看到的内容完全是两个世界——列表是空的、数据不在HTML里、只剩一堆<script>和<div id"app">的空壳。这就是典型的Jav…

作者头像 李华