作为一个常年和代码打交道的程序员,我发现自己越来越离不开终端。从最初的抗拒到现在的依赖,终端已经成为我日常工作不可或缺的一部分。有一天我突然想到:既然能在终端里写代码、调试程序,为什么不能用它来看小说呢?
传统的阅读方式要么需要专门的阅读软件,要么得打开显眼的文档窗口,在办公环境下显得过于招摇。而终端阅读器则完美解决了这个问题——在旁人看来,你只是在认真工作,没人会想到你其实沉浸在精彩的小说情节中。更重要的是,终端阅读器几乎不占系统资源,响应速度极快,完全不会影响正常工作。
PowerShell作为Windows平台最强大的脚本工具,配合VSCode这个程序员最爱的编辑器,简直是打造终端阅读器的绝佳组合。我实测下来,用这个方案读小说不仅隐蔽性高,还能自定义各种阅读参数,比那些臃肿的阅读软件不知道高到哪里去了。
首先确保你已经安装了最新版的VSCode和PowerShell。VSCode可以从官网直接下载安装,而Windows 10及以上系统已经内置了PowerShell 5.1或更高版本。我建议使用PowerShell 7.x,它在跨平台支持和性能上都有显著提升。
安装完成后,打开VSCode,按Ctrl+`(反引号键)打开集成终端。在终端右上角的下拉菜单中,确保选择了PowerShell作为默认终端。如果没看到PowerShell选项,可能需要安装PowerShell扩展。
将你想要阅读的小说保存为UTF-8编码的纯文本文件(.txt)。这里有个小技巧:很多网络小说网站都提供TXT下载功能,你可以直接下载后用VSCode打开,按Ctrl+Shift+P搜索"更改文件编码",选择"以编码保存",然后选UTF-8。
我习惯把小说文件放在专门的目录下,比如D:\Novels。建议文件名不要用中文,避免路径处理时可能出现的问题。比如可以命名为novel1.txt、novel2.txt这样简单的名字。
让我们从一个最基本的脚本开始。新建一个reader.ps1文件,输入以下内容:
powershell复制$filePath = "D:\Novels\novel1.txt"
$content = Get-Content -Path $filePath -Encoding UTF8
foreach ($line in $content) {
Write-Output $line
Start-Sleep -Milliseconds 500
}
这个脚本做了三件事:
运行方法很简单:在VSCode终端中导航到脚本所在目录,输入.\reader.ps1即可。如果遇到执行策略限制,可以先运行Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass临时允许脚本执行。
逐行阅读体验不太好,我们改成每次显示一页内容。修改脚本如下:
powershell复制$filePath = "D:\Novels\novel1.txt"
$content = Get-Content -Path $filePath -Encoding UTF8 -Raw
$pageSize = 10 # 每页显示10行
$currentLine = 0
$totalLines = ($content -split "`n").Count
while ($currentLine -lt $totalLines) {
Clear-Host
$content -split "`n" | Select-Object -Skip $currentLine -First $pageSize | ForEach-Object {
Write-Output $_
}
$currentLine += $pageSize
Start-Sleep -Seconds 3 # 每3秒自动翻页
}
这个版本增加了分页功能,每页显示10行内容,3秒后自动翻页。Clear-Host命令会在每次翻页时清屏,让阅读体验更舒适。你可以根据需要调整$pageSize和Start-Sleep的参数值。
作为一个经常被打断的程序员,最烦的就是找不到上次读到哪了。我们来添加一个记录阅读位置的功能:
powershell复制$textFile = "D:\Novels\novel1.txt"
$bookmarkFile = "D:\Novels\novel1.bookmark"
# 检查是否有书签文件
if (Test-Path $bookmarkFile) {
$currentLine = [int](Get-Content $bookmarkFile)
} else {
$currentLine = 0
}
$content = Get-Content -Path $textFile -Encoding UTF8 -Raw
$lines = $content -split "`n"
$totalLines = $lines.Count
$pageSize = 10
while ($currentLine -lt $totalLines) {
Clear-Host
$lines | Select-Object -Skip $currentLine -First $pageSize | ForEach-Object {
Write-Output $_
}
$currentLine += $pageSize
$currentLine | Out-File -FilePath $bookmarkFile
# 按Enter手动翻页,不按则5秒后自动翻页
$host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown,IncludeKeyUp") | Out-Null
Start-Sleep -Seconds 5
}
现在脚本会在同目录下创建一个.bookmark文件,记录你当前的阅读位置。下次打开时会自动从上次的位置继续阅读。我特别喜欢这个功能,因为再也不用担心被工作打断后找不到读到哪里了。
为了让阅读体验更好,我们可以增加一些交互控制:
powershell复制# 前面的配置部分保持不变...
while ($currentLine -lt $totalLines) {
Clear-Host
$lines | Select-Object -Skip $currentLine -First $pageSize | ForEach-Object {
Write-Output $_
}
Write-Host "`n[n]下一页 [p]上一页 [q]退出 [数字]跳转行"
$key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown").Character
switch ($key) {
'n' { $currentLine += $pageSize }
'p' { $currentLine = [Math]::Max(0, $currentLine - $pageSize) }
'q' { exit }
default {
if ($key -match '\d') {
$jumpLine = Read-Host "输入跳转行号"
$currentLine = [Math]::Min($totalLines, [int]$jumpLine)
}
}
}
$currentLine | Out-File -FilePath $bookmarkFile
}
现在你可以:
这个交互系统让阅读体验更加灵活,特别是当你需要回顾前面的内容时,不用重新启动脚本。
黑底白字看久了眼睛累,我们可以给终端加点颜色:
powershell复制# 在输出内容前设置颜色
function Show-Page {
param(
[string[]]$lines,
[int]$startLine,
[int]$count
)
Clear-Host
Write-Host "=== 当前阅读: novel1.txt ===" -ForegroundColor Cyan
Write-Host "=== 进度: $startLine/$($lines.Count)行 ===" -ForegroundColor Yellow
Write-Host "--------------------------------`n" -ForegroundColor DarkGray
$lines | Select-Object -Skip $startLine -First $count | ForEach-Object {
Write-Host $_ -ForegroundColor Green
}
Write-Host "`n--------------------------------" -ForegroundColor DarkGray
}
# 修改主循环中的输出部分
Show-Page -lines $lines -startLine $currentLine -count $pageSize
现在终端会显示:
这样的配色不仅美观,还能减轻长时间阅读的视觉疲劳。你可以根据自己的喜好调整颜色,PowerShell支持16种基本颜色和RGB值。
作为一个数据控,我喜欢统计自己的阅读情况:
powershell复制$statsFile = "D:\Novels\novel1.stats"
$startTime = Get-Date
# 在退出时保存统计信息
Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
$endTime = Get-Date
$duration = $endTime - $startTime
$stats = @{
LastRead = $endTime
TotalTime = $duration.TotalMinutes
LinesRead = $currentLine
}
$stats | ConvertTo-Json | Out-File -FilePath $statsFile
}
# 在脚本开头加载统计信息
if (Test-Path $statsFile) {
$savedStats = Get-Content $statsFile | ConvertFrom-Json
Write-Host "上次阅读时间: $($savedStats.LastRead)" -ForegroundColor Magenta
Write-Host "累计阅读时长: $([math]::Round($savedStats.TotalTime,1)) 分钟" -ForegroundColor Magenta
Write-Host "已读行数: $($savedStats.LinesRead)/$totalLines" -ForegroundColor Magenta
Start-Sleep -Seconds 2
}
这个功能会记录:
数据会保存为JSON格式,下次打开时自动显示。我发现这个功能特别能激励自己多读书,看着累计阅读时间增长特别有成就感。
当处理超长小说时,直接读取整个文件可能会占用过多内存。我们可以改用流式读取:
powershell复制$stream = [System.IO.File]::OpenText($textFile)
try {
$lines = @()
$lineCount = 0
while ($null -ne ($line = $stream.ReadLine())) {
$lines += $line
$lineCount++
if ($lineCount % 1000 -eq 0) {
# 每1000行清理一次内存
[System.GC]::Collect()
}
}
} finally {
$stream.Close()
}
这种方法内存占用更小,适合处理几MB以上的大文件。我在测试中用它成功打开了20MB的小说文件,内存占用始终保持在较低水平。
为了让脚本更稳定,我们需要添加错误处理:
powershell复制try {
$content = Get-Content -Path $textFile -Encoding UTF8 -ErrorAction Stop
} catch {
Write-Host "无法读取文件: $textFile" -ForegroundColor Red
Write-Host "错误详情: $_" -ForegroundColor Red
exit 1
}
# 书签文件处理
if (Test-Path $bookmarkFile) {
try {
$currentLine = [int](Get-Content $bookmarkFile -ErrorAction Stop)
if ($currentLine -gt $totalLines) {
$currentLine = 0
Write-Host "书签位置超出范围,已重置" -ForegroundColor Yellow
}
} catch {
Write-Host "书签文件损坏,已重置" -ForegroundColor Yellow
$currentLine = 0
}
}
现在脚本会:
这些改进让脚本更加健壮,避免了各种边缘情况导致的崩溃。我在实际使用中遇到过文件被占用、书签损坏等各种问题,有了这些错误处理后体验好多了。
结合前面所有功能,这是最终的完整实现:
powershell复制<#
.SYNOPSIS
PowerShell终端小说阅读器
.DESCRIPTION
支持自动翻页、断点续读、交互控制的终端阅读器
#>
param(
[string]$filePath = "D:\Novels\novel1.txt",
[int]$pageSize = 10,
[int]$autoScrollDelay = 0 # 0表示禁用自动翻页
)
# 初始化文件路径
$bookmarkFile = "$filePath.bookmark"
$statsFile = "$filePath.stats"
$configFile = "$filePath.config.json"
# 加载配置
if (Test-Path $configFile) {
$config = Get-Content $configFile | ConvertFrom-Json
$pageSize = $config.PageSize
$autoScrollDelay = $config.AutoScrollDelay
}
# 阅读统计
$startTime = Get-Date
$totalLines = 0
$currentLine = 0
# 注册退出事件
Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action {
$endTime = Get-Date
$duration = $endTime - $startTime
$stats = @{
LastRead = $endTime
TotalTime = $duration.TotalMinutes
LinesRead = $currentLine
}
$stats | ConvertTo-Json | Out-File -FilePath $statsFile -Force
}
# 显示欢迎信息
function Show-Welcome {
Clear-Host
Write-Host "=== PowerShell终端阅读器 ===" -ForegroundColor Cyan
Write-Host "正在加载: $(Split-Path $filePath -Leaf)" -ForegroundColor Yellow
if (Test-Path $statsFile) {
$savedStats = Get-Content $statsFile | ConvertFrom-Json
Write-Host "上次阅读: $($savedStats.LastRead)" -ForegroundColor Magenta
Write-Host "累计时长: $([math]::Round($savedStats.TotalTime,1)) 分钟" -ForegroundColor Magenta
}
Write-Host "`n[n]下一页 [p]上一页 [数字]跳转行" -ForegroundColor DarkGray
Write-Host "[s]设置 [q]退出 [a]自动翻页`n" -ForegroundColor DarkGray
Write-Host "--------------------------------`n" -ForegroundColor DarkGray
}
# 显示页面内容
function Show-Page {
param([int]$startLine)
Clear-Host
Write-Host "=== $(Split-Path $filePath -Leaf) ===" -ForegroundColor Cyan
Write-Host "=== 进度: $startLine/$totalLines 行 ===" -ForegroundColor Yellow
Write-Host "--------------------------------`n" -ForegroundColor DarkGray
$lines | Select-Object -Skip $startLine -First $pageSize | ForEach-Object {
Write-Host $_ -ForegroundColor Green
}
Write-Host "`n--------------------------------" -ForegroundColor DarkGray
Write-Host "`n[n]下一页 [p]上一页 [数字]跳转行" -ForegroundColor DarkGray
Write-Host "[s]设置 [q]退出 [a]自动翻页`n" -ForegroundColor DarkGray
}
# 加载文本内容
try {
$content = Get-Content -Path $filePath -Encoding UTF8 -Raw -ErrorAction Stop
$lines = $content -split "`n"
$totalLines = $lines.Count
} catch {
Write-Host "无法读取文件: $filePath" -ForegroundColor Red
Write-Host "错误详情: $_" -ForegroundColor Red
exit 1
}
# 加载书签
if (Test-Path $bookmarkFile) {
try {
$currentLine = [int](Get-Content $bookmarkFile -ErrorAction Stop)
if ($currentLine -ge $totalLines) {
$currentLine = 0
Write-Host "书签已重置" -ForegroundColor Yellow
Start-Sleep -Seconds 1
}
} catch {
Write-Host "书签文件损坏" -ForegroundColor Yellow
$currentLine = 0
}
}
# 主循环
Show-Welcome
Start-Sleep -Seconds 2
while ($currentLine -lt $totalLines) {
Show-Page -startLine $currentLine
# 自动翻页模式
if ($autoScrollDelay -gt 0) {
Write-Host "自动翻页中... ($autoScrollDelay秒)" -ForegroundColor DarkYellow
$key = $null
$counter = 0
while ($counter -lt $autoScrollDelay -and $key -eq $null) {
if ($host.UI.RawUI.KeyAvailable) {
$key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown").Character
break
}
Start-Sleep -Seconds 1
$counter++
}
} else {
$key = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown").Character
}
switch -Regex ($key) {
'n' { $currentLine = [Math]::Min($totalLines, $currentLine + $pageSize) }
'p' { $currentLine = [Math]::Max(0, $currentLine - $pageSize) }
'q' { exit }
'a' {
$autoScrollDelay = Read-Host "输入自动翻页间隔(秒)"
$autoScrollDelay = [int]$autoScrollDelay
$config = @{
PageSize = $pageSize
AutoScrollDelay = $autoScrollDelay
}
$config | ConvertTo-Json | Out-File -FilePath $configFile -Force
}
's' {
$newPageSize = Read-Host "输入每页行数(当前:$pageSize)"
$pageSize = [int]$newPageSize
$config = @{
PageSize = $pageSize
AutoScrollDelay = $autoScrollDelay
}
$config | ConvertTo-Json | Out-File -FilePath $configFile -Force
}
'\d' {
$jumpLine = Read-Host "输入跳转行号(1-$totalLines)"
$currentLine = [Math]::Max(0, [Math]::Min($totalLines, [int]$jumpLine))
}
}
# 保存书签
$currentLine | Out-File -FilePath $bookmarkFile -Force
}
经过几个月的使用和迭代,我总结出一些实用技巧:
快捷键绑定:在VSCode的keybindings.json中添加以下绑定可以快速启动阅读器:
json复制{
"key": "ctrl+alt+r",
"command": "workbench.action.terminal.sendSequence",
"args": { "text": ".\\reader.ps1 -filePath \"D:\\Novels\\novel1.txt\"\u000D" }
}
这样按Ctrl+Alt+R就能直接打开上次阅读的小说。
多小说管理:创建一个library.json文件记录所有小说:
json复制[
{
"title": "三体",
"path": "D:\\Novels\\santi.txt",
"lastRead": "2023-05-20",
"progress": 0.32
},
{
"title": "活着",
"path": "D:\\Novels\\huozhe.txt",
"lastRead": "2023-05-18",
"progress": 0.78
}
]
然后修改脚本开头加载这个库文件,实现多小说切换。
主题定制:在脚本目录下创建theme.json:
json复制{
"titleColor": "Cyan",
"textColor": "Green",
"infoColor": "Yellow",
"borderColor": "DarkGray",
"backgroundColor": "Black"
}
这样可以根据心情随时更换配色方案。
阅读目标设置:我习惯在stats.json中设置每日阅读目标:
json复制{
"dailyGoal": 30, // 分钟
"weeklyGoal": 180,
"currentStreak": 7 // 连续阅读天数
}
这个小功能帮助我养成了每天阅读的好习惯。
文本预处理:有些小说文件格式不规范,可以添加预处理函数:
powershell复制function Preprocess-Text {
param([string]$text)
# 移除多余空行
$text = $text -replace "(?m)^\s*`r?`n", ""
# 统一换行符
$text = $text -replace "`r`n", "`n"
# 移除章节标题前的空格
$text = $text -replace "(?m)^\s+(第.+章)", "`$1"
return $text
}
这样阅读体验会更加整洁。
这套终端阅读系统我已经用了大半年,不仅帮我"安全"读完了十几本小说,还意外地提高了我的PowerShell技能。最让我惊喜的是,有几次同事看到我的终端还问我是什么高级调试工具,完全没发现其实是在看小说。