优化Markdown预览工具:临时文件清理与模板应用
立即解锁
发布时间: 2025-09-08 02:04:48 阅读量: 10 订阅数: 28 AIGC 


Go构建高效命令行工具
### 优化Markdown预览工具:临时文件清理与模板应用
在开发命令行工具时,文件处理是一项常见且重要的任务,特别是在处理临时文件和生成动态内容时。本文将详细介绍如何优化Markdown预览工具,包括清理临时文件和使用模板提高工具的灵活性和可维护性。
#### 清理临时文件
当前程序在创建临时文件后不会自动清理,多次运行工具会产生多个临时文件。例如:
```sh
$ go run main.go -file README.md
/tmp/mdp552496404.html
$ go run main.go -file README.md
/tmp/mdp016541878.html
$ ls -ltr /tmp/ | grep mdp
-rw------- 1 ricardo users 503 Apr 15 10:25 mdp807323568.html
-rw------- 1 ricardo users 503 Apr 15 10:27 mdp552496404.html
-rw------- 1 ricardo users 503 Apr 15 10:31 mdp016541878.html
```
为了保持系统整洁,我们需要手动删除这些临时文件。可以使用`os.Remove`函数,并结合`defer`语句确保在函数返回时删除文件。以下是更新后的`run`函数:
```go
func run(filename string, out io.Writer, skipPreview bool) error {
// Read all the data from the input file and check for errors
input, err := ioutil.ReadFile(filename)
if err != nil {
return err
}
htmlData := parseContent(input)
// Create temporary file and check for errors
temp, err := ioutil.TempFile("", "mdp*.html")
if err != nil {
return err
}
if err := temp.Close(); err != nil {
return err
}
outName := temp.Name()
fmt.Fprintln(out, outName)
if err := saveHTML(outName, htmlData); err != nil {
return err
}
if skipPreview {
return nil
}
defer os.Remove(outName)
return preview(outName)
}
```
使用`defer`语句的好处是,它可以确保在函数返回时执行资源清理操作。但需要注意的是,使用`os.Exit`会立即退出程序,不会执行任何延迟函数调用。
自动删除文件会引入一个小的竞态条件:浏览器可能在文件被删除之前没有足够的时间打开它。为了解决这个问题,可以在`preview`函数返回之前添加一个小的延迟:
```go
import (
"bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"runtime"
"time"
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday/v2"
)
func preview(fname string) error {
cName := ""
cParams := []string{}
// Define executable based on OS
switch runtime.GOOS {
case "linux":
cName = "xdg-open"
case "windows":
cName = "cmd.exe"
cParams = []string{"/C", "start"}
case "darwin":
cName = "open"
default:
return fmt.Errorf("OS not supported")
}
// Append filename to parameters slice
cParams = append(cParams, fname)
// Locate executable in PATH
cPath, err := exec.LookPath(cName)
if err != nil {
return err
}
// Open the file using default program
err = exec.Command(cPath, cParams...).Run()
// Give the browser some time to open the file before deleting it
time.Sleep(2 * time.Second)
return err
}
```
添加延迟只是一个临时解决方案,后续可以通过处理信号或创建小型Web服务器来更好地解决这个问题。
执行测试确保所有测试通过:
```sh
$ go test -v
=== RUN TestParseContent
--- PASS: TestParseContent (0.00s)
=== RUN TestRun
--- PASS: TestRun (0.00s)
PASS
ok pragprog.com/rggo/workingFiles/mdp 0.009s
```
构建并执行新工具,预览文件会自动在浏览器中打开,并且临时文件会自动从临时目录中删除:
```sh
$ go build
$ ./mdp -file README.md
/tmp/mdp335221060.html
$ ls -l /tmp/mdp335221060.html
ls: cannot access '/tmp/mdp335221060.html': No such file or directory
```
在Linux/Unix-like系统上,还可以创建一个脚本,在文件内容更改时自动预览Markdown文件:
```sh
#!/bin/bash
FHASH=`md5sum $1`
while true; do
NHASH=`md5sum $1`
if [ "$NHASH" != "$FHASH" ]; then
./mdp -file $1
FHASH=$NHASH
fi
sleep 5
done
```
将脚本设置为可执行:
```sh
$ chmod +x autopreview.sh
```
运行脚本并指定要监视的文件:
```sh
$ ./autopreview.sh README.md
```
当在文本编辑器中更改并保存`README.md`文件时,浏览器会自动显示预览文件。使用`Ctrl+C`停止脚本。
#### 使用模板改进Markdown预览工具
当前工具的HTML头和页脚是硬编码的,这使得工具的灵活性和可维护性较差。为了解决这个问题,可以使用`html/template`包创建数据驱动的模板,允许在运行时将代码注入到预定义的位置。
首先,将`html/template`包添加到导入列表中:
```go
import (
"bytes"
"flag"
"fmt"
"io"
"html/template"
"io/ioutil"
"os"
"os/exec"
"runtime"
"time"
"github.
```
0
0
复制全文
相关推荐










