使用python开发终端查看工具
在本文中,我们将探讨如何使用Python开发一个终端查看器。这个查看器能够高亮显示多种编程语言的代码,并支持查看Markdown文件、Excel表格、CSV文件、各种编程语言文件文档等多种文件格式。
项目地址
git clone https://gitee.com/ezemeti/CmdSeeFile.git
安装依赖
首先,我们需要安装一些依赖。
pip install nbformat openpyxl pandas pyinstaller python-docx rich
库介绍
-
•
nbformat
:用于处理Jupyter Notebook文件 -
•
openpyxl
:用于处理Excel文件 -
•
pandas
:用于处理Excel文件,依赖于openpyxl
-
•
pyinstaller
:用于打包Python程序 -
•
python-docx
:用于处理Word文档 -
•
rich
:用于美化终端输出
导入库
接下来,我们导入所需的库。
import os
from rich.console import Console
from rich.syntax import Syntax
from rich.markdown import Markdown
from rich.table import Table
import pandas as pd
import docx
import argparse
import nbformat
console = Console()
设置需要处理的文件类型
接下来,我们设置需要处理的文件类型。
# 定义一个字典来映射文件后缀名到语言或格式
SUFFIX_MAP = {
".py": "python",
".java": "java",
".js": "javascript",
".json": "json",
".md": "markdown",
".text": "text",
".txt": "text",
".xlsx": "excel",
".xls": "excel",
".csv": "csv",
".docx": "word",
".ipynb": "jupyter",
".html": "html",
".css":"css",
".xml": "xml",
".sh": "shell",
".bat": "batch",
".go": "go",
".c": "c",
".cpp": "cpp",
".c++": "cpp",
".c#": "csharp",
".cs":"csharp",
".php": "php",
".rb": "ruby",
".rs": "rust",
".vue": "vue",
".yml": "yaml",
".ts": "typescript",
".tsx": "typescript",
".scss": "scss",
".less": "less",
}
定义函数来处理文件
现在,我们定义一个函数来处理文件。
def highlight_code(file_path, language, lines=True):
"""
:param file_path: 文件路径
:param language: 语言或格式
:param lines: 是否显示行号
:return: None
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
code = f.read()
syntax = Syntax(code, language, word_wrap=True, line_numbers=lines)
console.print(syntax)
except Exception as e:
console.print(f"读取文件时出错: {file_path}n{e}")
传入的参数有:
-
•
file_path
:文件路径 -
•
language
:语言或格式 -
•
lines
:是否显示行号(默认为True)
该函数用于高亮显示代码文件中的代码,并在控制台中输出。函数的输入参数有文件路径,语言类型和是否显示行号。函数会尝试打开文件,读取其中的代码,然后使用Syntax类对代码进行格式化,根据输入参数决定是否进行换行和显示行号。最后,通过console.print方法将格式化后的代码输出到控制台中。如果在读取文件的过程中出现异常,函数会将错误信息输出到控制台中
定义函数来处理Markdown文件
def render_markdown(file_path):
"""
:param file_path: Markdown文件路径
:return: None
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
markdown_text = f.read()
md = Markdown(markdown_text)
console.print(md)
except Exception as e:
console.print(f"读取Markdown文件时出错: {file_path}n{e}")
这个函数用于渲染Markdown文件的内容。它接受一个参数file_path,表示Markdown文件的路径,然后尝试打开这个文件,读取其中的内容。接下来,将读取到的Markdown文本传递给Markdown类的实例md,并使用console.print方法将渲染后的结果输出到控制台。如果在读取文件或渲染过程中发生任何异常,函数将捕获这个异常,并输出错误信息到控制台。
定义函数来处理Excel文件
def read_excel(file_path, title, sheet_name=None):
"""
:param file_path: Excel文件路径
:param title: 文件名
:param sheet_name: 工作表名
:return: None
"""
try:
# 读取 Excel 文件并获取所有工作表的名称
xls = pd.ExcelFile(file_path)
sheet_names = xls.sheet_names
# 显示文件名
console.print(f"[red]{title}[/red]")
# 根据用户输入决定显示哪个工作表
if sheet_name is None or sheet_name == "*":
# 显示所有工作表或默认显示第一个工作表
sheets_to_display = sheet_names if sheet_name == "*" else [sheet_names[0]]
elif sheet_name in sheet_names:
# 显示指定的工作表
sheets_to_display = [sheet_name]
else:
# 如果指定的工作表不存在,则显示错误消息
console.print(f"工作表 '{sheet_name}' 不存在。")
return
# 遍历每个要显示的工作表
for sheet_name in sheets_to_display:
# 读取当前工作表的数据
df = pd.read_excel(xls, sheet_name=sheet_name)
table = Table(title=f"工作表: {sheet_name}")
# 为表格添加列
for column in df.columns:
table.add_column(column, justify="left", style="cyan", no_wrap=False) # no_wrap参数用于禁止自动换行
# 为表格添加行
for row in df.itertuples(index=False):
table.add_row(*[str(item) for item in row])
# 打印表格
console.print(table)
except Exception as e:
console.print(f"读取Excel文件时出错: {file_path}n{e}")
该函数用于读取Excel文件并根据用户指定的工作表名显示对应的工作表数据。
函数接收三个参数:
-
•
file_path
: 表示Excel文件路径, -
•
title
: 表示文件名, -
•
sheet_name
: 表示工作表名,默认为None。*
显示所有工作表,None
显示默认工作表,若sheet_name
存在于工作表名称列表中,则显示指定的工作表。
函数主要实现以下功能:
-
• 根据用户输入的工作表名,决定显示的工作表。若
sheet_name
为None
或*
,则显示所有工作表或默认显示第一个工作表;若sheet_name
存在于工作表名称列表中,则显示指定的工作表;否则显示错误消息。 -
• 遍历每个要显示的工作表,读取其数据并以表格形式打印出来。表格的列标题为工作表中的列名,表格的行数据为工作表中的行数据。
-
• 若在读取Excel文件过程中出现异常,则打印错误消息
定义函数来处理CSV文件
def read_csv(file_path, title):
"""
:param file_path: CSV文件路径
:param title: 文件名
:return: None
"""
try:
df = pd.read_csv(file_path)
table = Table(title=title)
for column in df.columns:
table.add_column(column, justify="left", style="magenta", no_wrap=None)
for row in df.itertuples(index=False):
table.add_row(*[str(item) for item in row])
console.print(table)
except Exception as e:
console.print(f"读取CSV文件时出错: {file_path}n{e}")
该函数用于读取CSV文件并根据用户指定的文件名显示对应的数据。
函数接收两个参数:
-
•
file_path
: 表示CSV文件路径, -
•
title
: 表示文件名。
这个函数的功能是读取指定路径的CSV文件,并以一个自定义标题的表格形式在控制台中打印出来。函数使用了pandas库来读取CSV文件并将其转换为DataFrame,然后使用tabulate库将DataFrame格式化为表格。在表格中,列标题的对齐方式为左对齐,样式为洋红色。行数据通过遍历DataFrame的每一行,并将每个元素转换为字符串后添加到表格中。如果在读取CSV文件的过程中出现异常,函数会打印出错误信息。
定义函数来处理Jupyter文件
def read_jupyter(file_path):
# 读取notebook文件
with open(file_path, 'r', encoding='utf-8') as f:
nb = nbformat.read(f, as_version=4)
# 遍历所有单元格并打印内容
for cell in nb.cells:
if cell.cell_type == 'code':
# 对于代码单元格,打印源代码
md = Markdown("# 代码单元格 #")
console.print(md)
syntax = Syntax(cell.source, "python", word_wrap=True)
console.print(syntax)
mdl = Markdown("---")
console.print(mdl)
# 如果需要,也可以打印输出
if 'outputs' in cell and cell.outputs:
for output in cell.outputs:
if output.output_type == 'stream':
mdl = Markdown("### 执行结果 ###")
console.print(mdl)
print(output.text)
mdl = Markdown("---")
console.print(mdl)
elif output.output_type == 'execute_result':
print(output.data.get('text/plain', ''))
mdl = Markdown("---")
console.print(mdl)
elif cell.cell_type == 'markdown':
# 对于Markdown单元格,打印渲染后的HTML
html = nbformat.v4.new_markdown_cell(cell.source)
mdl = Markdown("# Markdown单元格 #")
console.print(mdl)
mar = Markdown(html['source'])
console.print(mar)
mdl = Markdown("---")
console.print(mdl)
else:
# 对于其他类型的单元格,直接打印内容
print("### 其他单元格 ###")
print(cell.source)
mdl = Markdown("---")
console.print(mdl)
该函数用于读取Jupyter Notebook文件,并遍历所有单元格,根据单元格类型分别打印代码单元格、Markdown单元格或其他类型的单元格的内容。对于代码单元格,会打印源代码和执行结果;对于Markdown单元格,会打印渲染后的HTML。
在函数中,使用了nbformat
库来解析Notebook文件,并使用console
模块来打印输出。
定义main函数
def main(file_path, sheet_name=None, lines=True):
"""
:param file_path: 文件路径
:param sheet_name: 工作表名
:param lines: 是否显示行号
:return: None
"""
file_suffix = os.path.splitext(file_path)[1].lower()
file_name = os.path.basename(file_path)
if file_suffix in SUFFIX_MAP:
if SUFFIX_MAP[file_suffix] == "markdown":
render_markdown(file_path)
elif SUFFIX_MAP[file_suffix] == "excel":
read_excel(file_path, title=file_name, sheet_name=sheet_name)
elif SUFFIX_MAP[file_suffix] == "csv":
read_csv(file_path, title=file_name)
elif SUFFIX_MAP[file_suffix] == "word":
read_word(file_path, title=file_name)
elif SUFFIX_MAP[file_suffix] == "jupyter":
read_jupyter(file_path)
else:
highlight_code(file_path, SUFFIX_MAP[file_suffix], lines)
else:
console.print(f"不支持文件格式: {file_path}")
接受三个参数:
-
•
file_path
:表示要处理的文件路径; -
•
sheet_name
:表示要显示的工作表名; -
•
lines
:表示是否显示行号。
该函数根据文件路径和扩展名,判断文件类型并进行相应的处理。如果文件类型是markdown,则渲染markdown文件;如果是excel、csv或word,则分别读取相应文件;如果是jupyter notebook,则读取jupyter文件;如果是其他代码文件,则高亮显示代码。如果文件扩展名不在支持的类型中,则输出不支持文件格式的提示信息。
调用
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="读取文件")
parser.add_argument("file_path", help="要读取文件的路径")
parser.add_argument("sheet_name", nargs='?', default=None, help="要显示的工作表名称(对于Excel文件)。默认为第一个工作表,如果输入*,则显示所有工作表")
parser.add_argument("-l", "--lines", help="是否显示行数", action="store_true")
args = parser.parse_args()
if not os.path.isfile(args.file_path):
console.print(f"文件不存在: {args.file_path}")
else:
main(args.file_path, args.sheet_name, args.lines)
这段代码是一个命令行参数解析的功能模块。 使用argparse
库创建一个解析器parser
,并设置描述信息为”读取文件”;
通过add_argument
方法定义了三个参数:
-
•
file_path
:必选参数,表示要读取文件的路径; -
•
sheet_name
:可选参数,表示要显示的工作表名称(对于Excel文件)。默认为第一个工作表,如果输入*,则显示所有工作表; -
•
-l
/--lines
:可选参数,表示是否显示行数;
使用parse_args()
方法解析命令行传入的参数,并将解析结果存储在args变量中, 判断文件路径是否存在,如果不存在,则输出错误信息到控制台; 如果文件存在,则调用main
函数,传入文件路径、工作表名称和是否显示行数的参数。
运行
测试文件在test
文件夹中。
运行python see.py -h
可以查看帮助信息。
在命令行中运行该模块,可以传入文件路径、工作表名称和是否显示行数的参数,例如:
读取Markdown文件
python see.py test.md
读取Excel文件
读取默认工作表
python see.py test.xlsx
读取指定工作表
python see.py test.xlsx sheet1
读取所有工作表
python see.py test.xlsx *
读取编程文件或者其他文件
默认显示,不显示行号
python see.py test.py
显示行号
python see.py test.py -l
效果
打包成可执行文件
pyinstaller --onefile see.py
配置Windows环境变量
将see.exe
所在路径添加到path
环境变量中,这样就可以在任意路径下运行see.exe
了。
完整
import os
from rich.console import Console
from rich.syntax import Syntax
from rich.markdown import Markdown
from rich.table import Table
import pandas as pd
import docx
import argparse
import nbformat
console = Console()
# 定义一个字典来映射文件后缀名到语言或格式
SUFFIX_MAP = {
".py": "python",
".java": "java",
".js": "javascript",
".json": "json",
".md": "markdown",
".text": "text",
".txt": "text",
".xlsx": "excel",
".xls": "excel",
".csv": "csv",
".docx": "word",
".ipynb": "jupyter",
".html": "html",
".css":"css",
".xml": "xml",
".sh": "shell",
".bat": "batch",
".go": "go",
".c": "c",
".cpp": "cpp",
".c++": "cpp",
".c#": "csharp",
".cs":"csharp",
".php": "php",
".rb": "ruby",
".rs": "rust",
".vue": "vue",
".yml": "yaml",
".ts": "typescript",
".tsx": "typescript",
".scss": "scss",
".less": "less",
}
def highlight_code(file_path, language, lines=True):
"""
:param file_path: 文件路径
:param language: 语言或格式
:param lines: 是否显示行号
:return: None
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
code = f.read()
syntax = Syntax(code, language, word_wrap=True, line_numbers=lines)
console.print(syntax)
except Exception as e:
console.print(f"读取文件时出错: {file_path}n{e}")
def render_markdown(file_path):
"""
:param file_path: Markdown文件路径
:return: None
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
markdown_text = f.read()
md = Markdown(markdown_text)
console.print(md)
except Exception as e:
console.print(f"读取Markdown文件时出错: {file_path}n{e}")
def read_excel(file_path, title, sheet_name=None):
"""
:param file_path: Excel文件路径
:param title: 文件名
:param sheet_name: 工作表名
:return: None
"""
try:
# 读取 Excel 文件并获取所有工作表的名称
xls = pd.ExcelFile(file_path)
sheet_names = xls.sheet_names
# 显示文件名
console.print(f"[red]{title}[/red]")
# 根据用户输入决定显示哪个工作表
if sheet_name is None or sheet_name == "*":
# 显示所有工作表或默认显示第一个工作表
sheets_to_display = sheet_names if sheet_name == "*" else [sheet_names[0]]
elif sheet_name in sheet_names:
# 显示指定的工作表
sheets_to_display = [sheet_name]
else:
# 如果指定的工作表不存在,则显示错误消息
console.print(f"工作表 '{sheet_name}' 不存在。")
return
# 遍历每个要显示的工作表
for sheet_name in sheets_to_display:
# 读取当前工作表的数据
df = pd.read_excel(xls, sheet_name=sheet_name)
table = Table(title=f"工作表: {sheet_name}")
# 为表格添加列
for column in df.columns:
table.add_column(column, justify="left", style="cyan", no_wrap=False)
# 为表格添加行
for row in df.itertuples(index=False):
table.add_row(*[str(item) for item in row])
# 打印表格
console.print(table)
except Exception as e:
console.print(f"读取Excel文件时出错: {file_path}n{e}")
def read_csv(file_path, title):
"""
:param file_path: CSV文件路径
:param title: 文件名
:return: None
"""
try:
df = pd.read_csv(file_path)
table = Table(title=title)
for column in df.columns:
table.add_column(column, justify="left", style="magenta", no_wrap=False)
for row in df.itertuples(index=False):
table.add_row(*[str(item) for item in row])
console.print(table)
except Exception as e:
console.print(f"读取CSV文件时出错: {file_path}n{e}")
def read_word(file_path, title):
try:
doc = docx.Document(file_path)
console.print(f"{title}:")
for para in doc.paragraphs:
console.print(para.text)
except Exception as e:
console.print(f"读取Word文件时出错: {file_path}n{e}")
def read_jupyter(file_path):
# 读取notebook文件
with open(file_path, 'r', encoding='utf-8') as f:
nb = nbformat.read(f, as_version=4)
# 遍历所有单元格并打印内容
for cell in nb.cells:
if cell.cell_type == 'code':
# 对于代码单元格,打印源代码
md = Markdown("# 代码单元格 #")
console.print(md)
syntax = Syntax(cell.source, "python", word_wrap=True)
console.print(syntax)
mdl = Markdown("---")
console.print(mdl)
# 如果需要,也可以打印输出
if 'outputs' in cell and cell.outputs:
for output in cell.outputs:
if output.output_type == 'stream':
mdl = Markdown("### 执行结果 ###")
console.print(mdl)
print(output.text)
mdl = Markdown("---")
console.print(mdl)
elif output.output_type == 'execute_result':
print(output.data.get('text/plain', ''))
mdl = Markdown("---")
console.print(mdl)
elif cell.cell_type == 'markdown':
# 对于Markdown单元格,打印渲染后的HTML
html = nbformat.v4.new_markdown_cell(cell.source)
mdl = Markdown("# Markdown单元格 #")
console.print(mdl)
mar = Markdown(html['source'])
console.print(mar)
mdl = Markdown("---")
console.print(mdl)
else:
# 对于其他类型的单元格,直接打印内容
print("### 其他单元格 ###")
print(cell.source)
mdl = Markdown("---")
console.print(mdl)
def main(file_path, sheet_name=None, lines=True):
"""
:param file_path: 文件路径
:param sheet_name: 工作表名
:param lines: 是否显示行号
:return: None
"""
file_suffix = os.path.splitext(file_path)[1].lower()
file_name = os.path.basename(file_path)
if file_suffix in SUFFIX_MAP:
if SUFFIX_MAP[file_suffix] == "markdown":
render_markdown(file_path)
elif SUFFIX_MAP[file_suffix] == "excel":
read_excel(file_path, title=file_name, sheet_name=sheet_name)
elif SUFFIX_MAP[file_suffix] == "csv":
read_csv(file_path, title=file_name)
elif SUFFIX_MAP[file_suffix] == "word":
read_word(file_path, title=file_name)
elif SUFFIX_MAP[file_suffix] == "jupyter":
read_jupyter(file_path)
else:
highlight_code(file_path, SUFFIX_MAP[file_suffix], lines)
else:
console.print(f"不支持文件格式: {file_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="读取文件")
parser.add_argument("file_path", help="要读取文件的路径")
parser.add_argument("sheet_name", nargs='?', default=None, help="要显示的工作表名称(对于Excel文件)。默认为第一个工作表,如果输入*,则显示所有工作表")
parser.add_argument("-l", "--lines", help="是否显示行数", action="store_true")
args = parser.parse_args()
if not os.path.isfile(args.file_path):
console.print(f"文件不存在: {args.file_path}")
else:
main(args.file_path, args.sheet_name, args.lines)
原文始发于微信公众号(索隆程序员):基于python开发终端查看利器
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/251669.html