18 基于.NetCore開發博客項目 StarBlog - 實現本地Typora文章打包上傳

前言九月太忙 , 只更新了三篇文章,本來這個功能是從九月初就開始做的 , 結果一直拖到現在國慶假期才有時間完善并且寫文章~
之前我更新了幾篇關于 Python 的文章 , 有朋友留言問是不是不更新 .Net 了 , 那肯定不能??,我只能说「?全 都 要」 , 所以我反手就更新了一篇Asp-Net-Core開發筆記 。
然后順便立個Flag:今年底前完成StarBlog系列文章的主體部分(即API開發+后臺前端開發,目前只完成博客前后端部分),加油吧~
【18 基于.NetCore開發博客項目 StarBlog -實現本地Typora文章打包上傳】OK,說回本文,程序員都喜歡用Markdown來寫文章 , 但由于markdown是純文本格式,在其中插入的圖片要如何保存,就成了一大煩惱,有人選擇圖床,但不一定永久有效;有人選擇本地存儲,圖片永久有效,但如何分享文章又成了一個難題…
我選的就是第二種 , 本地存儲 。使用Typora寫文章 , 圖片保存在和Markdown文件同名的目錄(markdown.assets)下,這樣可以獲得很好的寫作體驗,然后分享的問題就交給StarBlog吧,這個項目開發的初衷就是為了把本地的文章發表成博客 。
不過之前只有批量導入文章的功能,現在我要做的就是單獨實現一個單篇文章打包導入的功能 。

隨著文章越來越多,系列文章的目錄放前面有點影響閱讀了,所以從這篇開始我把它放到最后面~
實現思路假設我用Typora寫了一篇Markdown文章,文件名為:StarBlog.md,并且在里面插入了若干圖片,根據配置 , Typora會自動生成一個目錄(StarBlog.assets)來存放這些圖片 。
為了實現導入,我要把這個markdown文件和這個存圖片的目錄一起打包成zip壓縮文件上傳,后端將zip壓縮包解壓到臨時目錄 , 讀取Markdown文件,解析其中的內容,進行導入操作 。
代碼實現OK,開始寫代碼吧
同時所有項目代碼已經上傳GitHub,歡迎各位大佬Star/Fork!
  • 博客后端+前臺項目地址:https://github.com/Deali-Axy/StarBlog
  • 管理后臺前端項目地址:https://github.com/Deali-Axy/StarBlog-Admin
解壓縮首先是解壓縮功能,.Net標準庫自帶 ZipFile 這個庫用于操作zip壓縮包,在 System.IO.Compression 里,直接用就完事了 。
解壓前得先把文件復制到臨時目錄,并創建一個新的臨時目錄來放解壓后的文件 。
Services/BlogServices.cs 里新增代碼
public async Task<Post> Upload(PostCreationDto dto, IFormFile file) {// 先復制到臨時文件var tempFile = Path.GetTempFileName();await using (var fs = new FileStream(tempFile, FileMode.Create)) {await file.CopyToAsync(fs);}// 設定解壓用的臨時目錄var extractPath = Path.Combine(Path.GetTempPath(), "StarBlog", Guid.NewGuid().ToString());// 使用 GBK 編碼解壓,防止中文文件名亂碼Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);ZipFile.ExtractToDirectory(tempFile, extractPath, Encoding.GetEncoding("GBK"));}本來直接 ZipFile.ExtractToDirectory() 就能解壓了,但如果壓縮包里的文件用了中文名,就得先設置編碼 。
解析Markdown關于 C# 解析 Markdown ,在本系列一開始就寫過,所以這里就不再當復讀機了,可以直接看這兩篇文章:
  • 基于.NetCore開發博客項目 StarBlog - (4) markdown博客批量導入
  • C#解析Markdown文檔,實現替換圖片鏈接操作
直接上代碼了
因為是做單篇文章導入,所以我這里獲取臨時目錄寫的所有 *.md 文件之后只取第一個文件來處理(理論上也不應該有多個~)
var dir = new DirectoryInfo(extractPath);var files = dir.GetFiles("*.md");var mdFile = files.First();using var reader = mdFile.OpenText();var content = await reader.ReadToEndAsync();var post = new Post {Id = GuidUtils.GuidTo16String(),Status = "已發布",Title = dto.Title ?? $"{DateTime.Now.ToLongDateString()} 文章",IsPublish = true,Content = content,Path = "",CreationTime = DateTime.Now,LastUpdateTime = DateTime.Now,CategoryId = dto.CategoryId,};var assetsPath = Path.Combine(_environment.WebRootPath, "media", "blog");var processor = new PostProcessor(extractPath, assetsPath, post);// 處理文章標題和狀態processor.InflateStatusTitle();// 處理文章正文內容// 導入文章的時候一并導入文章里的圖片 , 并對圖片相對路徑做替換操作post.Content = processor.MarkdownParse();post.Summary = processor.GetSummary(200);Markdown相關的處理,我封裝了 PostProcessor 這個對象,在 StarBlog.Share

推薦閱讀