在平時的工做或學習中,咱們常常會接觸不一樣格式的文檔類型,好比txt,log,Offices文檔,編程代碼腳本,圖片,視頻等。本文將會介紹筆者的一個樸素想法,即把不一樣格式的文檔都放在同一個平臺中進行預覽,這樣既方便查看常見文檔,又能提高工做和學習效率。
本項目的工程結構以下:
本項目如今已支持8種文檔格式的格式,分別爲:javascript
首先,咱們須要下載前端的PDF預覽JS框架PDF.js
,它是一個網頁端的PDF文件解析和預覽框架,下載網址爲:http://mozilla.github.io/pdf.js/ 。
接着,本項目還用到了showdown.js
,該JS框架用於渲染Markdown文檔。
用Python作後端,tornado爲web框架,筆者使用的版本爲5.1.1
。css
咱們下載PDF.js
項目代碼,並在/pdfjs/web
目錄下新建files
文件夾,用於存放上傳的文件。爲了可以用PDF.js
實現PDF文件預覽,須要切換至pdfjs文件夾,運行搭建文件服務器命令:html
python -m http.server 8081
或者:前端
python -m SimpleHTTPServer 8081
接着介紹HTML文件,index.html
是首頁代碼,主要實現文件上傳功能,代碼以下:java
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>文件上傳</title> </head> <body> <div align="center"> <br><br> <h1>文件上傳</h1> <form action='file' enctype="multipart/form-data" method='post'> <div class="am-form-group am-form-file"> <input id="doc-form-file" type="file" name="file" multiple> </div> <div id="file-list"></div> <p> <button type="submit" class="am-btn am-btn-default">提交</button> </p> </form> </div> </body> </html>
頁面以下(有點兒過於簡單,還好本項目是注重文檔預覽功能):
markdown.html
主要用於展現Markdown文件中的內容,代碼以下:python
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Markdown文件展現</title> <script src="https://cdn.bootcss.com/showdown/1.9.0/showdown.min.js"></script> <script> function convert(){ var converter = new showdown.Converter(); var text = "{{ md_content }}"; var html = converter.makeHtml(text.replace(/newline/g, "\n")); document.getElementById("result").innerHTML = html; } </script> </head> <body onload="convert()"> <div id="result" ></div> </body> </html>
注意,咱們在head部分引用了showdown.js
的CDN地址,這樣就不用下載該項目文件了。
最後是後端部分,採用Python的Tornado模塊實現。tornado_file_receiver.py
主要用於文檔的上傳和保存,並展現文檔內容,完整代碼以下:git
# -*- coding: utf-8 -*- import os import logging import traceback import tornado.ioloop import tornado.web from tornado import options from parse_file import * # 文檔上傳與解析 class UploadFileHandler(tornado.web.RequestHandler): # get函數 def get(self): self.render('upload.html') def post(self): # 文件的存放路徑 upload_path = os.path.join(os.path.dirname(__file__), 'pdfjs/web/files') # 提取表單中‘name’爲‘file’的文件元數據 # 暫時只支持單文檔的上傳 file_meta = self.request.files['file'][0] filename = file_meta['filename'] # 保存文件 with open(os.path.join(upload_path, filename), 'wb') as up: up.write(file_meta['body']) text = file_meta["body"] # 解析文件的內容 mtype = file_meta["content_type"] logging.info('POST "%s" "%s" %d bytes', filename, mtype, len(text)) if mtype in ["text/x-python", "text/x-python-script"]: self.write(parse_python(str(text, encoding="utf-8"))) elif mtype in ["text/plain", "text/csv"]: self.write(parse_text_plain(str(text, encoding="utf-8"))) elif mtype == "text/html": self.write(str(text, encoding="utf-8")) elif mtype.startswith("image"): self.write(parse_image(mtype, text)) elif mtype == "application/json": self.write(parse_application_json(str(text, encoding="utf-8"))) elif mtype == "application/pdf": self.redirect("http://127.0.0.1:8081/web/viewer.html?file=files/%s" % filename) elif mtype == "application/octet-stream" and filename.endswith(".md"): self.render("markdown.html", md_content=r"%s" % str(text, encoding="utf-8").replace("\n", "newline")) else: # 其他文件格式 try: self.write(str(text, encoding="utf-8").replace("\n", "<br>")) except Exception: logging.error(traceback.format_exc()) self.write('<font color=red>系統不支持的文件解析格式!</font>') def make_app(): return tornado.web.Application([(r"/file", UploadFileHandler)], template_path=os.path.join(os.path.dirname(__file__), "templates")) # 模板路徑 if __name__ == "__main__": # Tornado configures logging. options.parse_command_line() app = make_app() app.listen(8888) tornado.ioloop.IOLoop.current().start()
parse_file.py
用於解析各類格式的文檔,並返回HTML展現的格式,完整代碼以下:github
# -*- coding: utf-8 -*- # author: Jclian91 # place: Pudong Shanghai # time: 2020/6/5 1:05 下午 # filename: parse_file.py # 用於解析各類文件類型的數據 import json import base64 import logging import traceback from json import JSONDecodeError # 解析text/plain或者text/csv文件格式 def parse_text_plain(text): return "<html><head></head><body>%s</body></html>" % text.replace("\n", "<br>") # 解析application/json文件格式 def parse_application_json(text): try: data_dict = json.loads(text) return json.dumps(data_dict, ensure_ascii=False, indent=2).replace("\n", "<br>").replace(" ", " ") except JSONDecodeError: try: data_list = [json.loads(_) for _ in text.split("\n") if _] return json.dumps(data_list, ensure_ascii=False, indent=2).replace("\n", "<br>").replace(" ", " ") except JSONDecodeError: logging.error(traceback.format_exc()) return "JSON文件格式解析錯誤" except Exception as err: logging.error(traceback.format_exc()) return "未知錯誤: %s" % err # 解析image/*文件格式 def parse_image(mtype, text): return '<html><head></head><body><img src="data:%s;base64,%s"></body></html>' % \ (mtype, str(base64.b64encode(text), "utf-8")) # 解析Python文件 def parse_python(text): # indent和換行 text = text.replace("\n", "<br>").replace(" ", " ").replace("\t", " " * 4) # 關鍵字配色 color_list = ["gray", "red", "green", "blue", "orange", "purple", "pink", "brown", "wheat", "seagreen", "orchid", "olive"] key_words = ["self", "from", "import", "def", ":", "return", "open", "class", "try", "except", '"', "print"] for word, color in zip(key_words, color_list): text = text.replace(word, '<font color=%s>%s</font>' % (color, word)) colors = ["peru"] * 7 punctuations = list("[](){}#") for punctuation, color in zip(punctuations, colors): text = text.replace(punctuation, '<font color=%s>%s</font>' % (color, punctuation)) html = "<html><head></head><body>%s</body></html>" % text return html
下面將進一步介紹各類格式實現預覽的機制。web
html文件的MIMETYPE爲text/html
,因爲本項目採用HTML展現,所以對於text/html
的文檔,直接返回其內容就能夠了。
從Tornado的代碼中咱們能夠看出,filename變量爲文檔名稱,text爲文檔內容,bytes字符串。在前端展現的時候,咱們返回其文檔內容:編程
self.write(str(text, encoding="utf-8"))
其中,str(text, encoding="utf-8")
是將bytes字符串轉化爲UTF-8編碼的字符串。
txt/log等文件的MIMETYPE爲text/plain
,其與HTML文檔的不一樣之處在於,若是須要前端展現,須要在返回的字符中添加HTML代碼,以下(parse_file.py
中的代碼):
# 解析text/plain或者text/csv文件格式 def parse_text_plain(text): return "<html><head></head><body>%s</body></html>" % text.replace("\n", "<br>")
csv格式文件的MIMETYPE爲text/csv
,其預覽的方式與txt/log等格式的文檔一致。
但csv是逗號分隔文件,數據格式是表格形式,所以在前端展現上應該有更好的效果。關於這一格式的文檔,其前端預覽的更好方式能夠參考文章: 利用tornado實現表格文件預覽 。
關於json文件的預覽,筆者更關注的是json文件的讀取。這裏處理兩種狀況,一種是整個json文件就是json字符串,另外一種狀況是json文件的每一行都是json字符串。在前端展現的時候,採用json.dumps中的indent參數實現縮進,並轉化爲html中的空格,實現方式以下(parse_file.py
中的代碼):
# 解析application/json文件格式 def parse_application_json(text): try: data_dict = json.loads(text) return json.dumps(data_dict, ensure_ascii=False, indent=2).replace("\n", "<br>").replace(" ", " ") except JSONDecodeError: try: data_list = [json.loads(_) for _ in text.split("\n") if _] return json.dumps(data_list, ensure_ascii=False, indent=2).replace("\n", "<br>").replace(" ", " ") except JSONDecodeError: logging.error(traceback.format_exc()) return "JSON文件格式解析錯誤" except Exception as err: logging.error(traceback.format_exc()) return "未知錯誤: %s" % err
筆者相信必定有json文件更好的前端展現方式,這裏沒有采用專門處理json的JS框架,這之後做爲後續的改進措施。
PDF文檔的展現略顯複雜,本項目藉助了PDF.js
的幫助,咱們須要它來搭建PDF預覽服務,這點在上面的項目代碼
部分的開頭已經講了。
搭建好PDF預覽服務後,因爲上傳的文件都會進入pdfjs/web/files
目錄下,所以PDF文檔預覽的網址爲:http://127.0.0.1:8081/web/viewer.html?file=files/pdf_name ,其中pdf_name爲上傳的PDF文檔名稱。
有了這個PDF預覽服務後,咱們展現PDF文檔的代碼就很簡單了(tornado_file_receiver.py
中的代碼):
elif mtype == "application/pdf": self.redirect("http://127.0.0.1:8081/web/viewer.html?file=files/%s" % filename)
Python腳本的處理方式並不複雜,無非是在把Python文檔轉化爲HTML文件格式的時候,加入縮進、換行處理,以及對特定的Python關鍵字進行配色,所以代碼以下(parse_file.py
中的代碼):
# 解析Python文件 def parse_python(text): # indent和換行 text = text.replace("\n", "<br>").replace(" ", " ").replace("\t", " " * 4) # 關鍵字配色 color_list = ["gray", "red", "green", "blue", "orange", "purple", "pink", "brown", "wheat", "seagreen", "orchid", "olive"] key_words = ["self", "from", "import", "def", ":", "return", "open", "class", "try", "except", '"', "print"] for word, color in zip(key_words, color_list): text = text.replace(word, '<font color=%s>%s</font>' % (color, word)) colors = ["peru"] * 7 punctuations = list("[](){}#") for punctuation, color in zip(punctuations, colors): text = text.replace(punctuation, '<font color=%s>%s</font>' % (color, punctuation)) html = "<html><head></head><body>%s</body></html>" % text return html
根據筆者的瞭解,其實有更好的Python腳本內容的預覽方式,能夠藉助handout
模塊實現,這點筆者將會在後續加上。
圖片文件在HTML上的展現有不少中,筆者採用的方式爲:
<img src="data:image/png;base64,ABKAMNDKSJFHVCJSNVOIEJHVUEHVUV==">
就是對圖片讀取後的字符串進行base64編碼便可,所以實現代碼以下(parse_file.py
中的代碼):
import base64 # 解析image/*文件格式 def parse_image(mtype, text): return '<html><head></head><body><img src="data:%s;base64,%s"></body></html>' % \ (mtype, str(base64.b64encode(text), "utf-8"))
markdown文件的預覽稍顯複雜,藉助showdown.js
和不斷的嘗試探索,因爲markdown在讀取後的換行符\n
在轉化爲JavaScript字符串時並不須要轉義,這是實現預覽的難點。筆者的作法是把Python讀取的markdown中的換行符\n
轉化爲newline
,並在JS渲染的時候才把newline
替換成\n
,這就解決了不須要轉移的難題。具體的實現能夠參考markdown.html
,如今Python後端代碼中把Python讀取的markdown中的換行符\n
轉化爲newline
,代碼以下:
elif mtype == "application/octet-stream" and filename.endswith(".md"): self.render("markdown.html", md_content=r"%s" % str(text, encoding="utf-8").replace("\n", "newline"))
接着在markdown.html
中的JS部分把Python讀取的markdown中的換行符\n
轉化爲newline
,代碼以下:
<script> function convert(){ var converter = new showdown.Converter(); var text = "{{ md_content }}"; var html = converter.makeHtml(text.replace(/newline/g, "\n")); document.getElementById("result").innerHTML = html; } </script>
下面將給出上述8中文檔格式在本系統中的預覽效果。
上傳文件爲reponse.html
,預覽效果以下:
上傳文件爲info.log,預覽效果以下:
上傳文件爲iris.csv,預覽效果以下:
上傳文件爲test1.json,預覽效果以下:
上傳文件爲,預覽效果以下:
上傳文件爲test.py,預覽效果以下:
上傳圖片爲ffe3d40029eae71ccf8587e5dc21d58d.jpg,預覽效果以下:
上傳文件爲Scrapy爬取動態網頁.md,預覽效果以下:
爲了證實上面的預覽確實是筆者已經實現的,而不是從哪搬來的圖片,特放上程序運行記錄以及files目錄下的文件,以下:
本項目已經開源至Github,網址爲https://github.com/percent4/document_reviewer 。
本項目如今支持的文檔格式還比較少,後續能夠增長更好文檔格式的支持,另外,如今的文檔格式的預覽有些能夠作得更好,後續也會進行優化~
感謝你們閱讀,但願讀者多多批評指正~