群晖NAS的osheet文件打不开?用Python写个脚本,5分钟批量转成Excel

张开发
2026/4/18 13:22:24 15 分钟阅读

分享文章

群晖NAS的osheet文件打不开?用Python写个脚本,5分钟批量转成Excel
群晖NAS的osheet文件打不开用Python写个脚本5分钟批量转成Excel如果你是一位群晖NAS用户可能会遇到这样的困扰通过Drive同步到本地的表格文件扩展名变成了.osheet用Office或WPS打开时一片空白。这种专有格式虽然方便群晖在线协作却给本地编辑带来了麻烦。别担心本文将带你用Python编写一个轻量级转换工具彻底解决这个痛点。.osheet文件本质上是结构化文本核心数据以JSON格式存储。通过分析文件内容我们可以提取其中的表格信息并转换为标准的Excel格式。整个过程不需要复杂的第三方库只需Python内置模块即可完成。1. 理解osheet文件结构首先用文本编辑器打开一个.osheet文件你会看到类似这样的内容x schema enc id # 1027_MQNCOFQNN90GT2AGIHOC62TSI0.sh ver ) 8948c4e945f51ccbb1165804d6dff3162e9bc290 text/comment [] text/define {} ? text/index ? {gcVer:1,maxIndex:2,order:[sh_1,sh_2],schemaVersion:5,sheets:{sh_1:{deleted:false,title:工作表1},sh_2:{deleted:false,title:工作表2}},ver:3}关键信息都包裹在{}中主要包括工作表定义sheets字段单元格数据cells字段样式信息可选注意文件包含非文本字符必须用二进制模式读取2. 搭建Python转换环境确保你的系统已安装Python 3.6然后创建一个新的项目目录mkdir osheet_converter cd osheet_converter python -m venv venv source venv/bin/activate # Linux/macOS venv\Scripts\activate # Windows安装唯一需要的第三方库用于生成Excel文件pip install xlsxwriter3. 编写核心转换脚本创建convert.py文件我们分步骤实现转换功能3.1 文件读取与JSON提取import json from pathlib import Path def extract_json_blocks(file_path): 从二进制文件中提取JSON数据块 with open(file_path, rb) as f: content f.read() json_blocks [] stack [] start_index 0 for i, byte in enumerate(content): if byte 123: # {的ASCII码 if not stack: start_index i stack.append(byte) elif byte 125: # }的ASCII码 if stack: stack.pop() if not stack: try: json_str content[start_index:i1].decode(utf-8) json.loads(json_str) # 验证有效性 json_blocks.append(json_str) except (UnicodeDecodeError, json.JSONDecodeError): continue return json_blocks3.2 数据结构解析提取的JSON块包含以下关键信息字段路径说明示例值sheets工作表定义{sh_1: {title: Sheet1}}cells单元格数据{0: {0: {v: Hello}}}rowCount行数100colCount列数303.3 Excel写入实现import xlsxwriter def convert_to_excel(json_blocks, output_path): 将解析的JSON数据写入Excel文件 workbook xlsxwriter.Workbook(output_path) # 提取工作表信息 sheets_info {} for block in json_blocks: data json.loads(block) if sheets in data: sheets_info data[sheets] # 写入单元格数据 for block in json_blocks: data json.loads(block) if cells in data: sheet_id next((k for k in data.keys() if k.startswith(sh_)), None) if sheet_id and sheet_id in sheets_info: sheet_name sheets_info[sheet_id][title] worksheet workbook.add_worksheet(sheet_name) for row_num, row_data in data[cells].items(): for col_num, cell_data in row_data.items(): worksheet.write(int(row_num), int(col_num), cell_data[v]) workbook.close()4. 添加批量处理功能为了提升效率我们扩展脚本支持批量转换from concurrent.futures import ThreadPoolExecutor import time def batch_convert(input_folder, output_folder): 批量转换文件夹中的所有osheet文件 input_path Path(input_folder) output_path Path(output_folder) output_path.mkdir(exist_okTrue) osheet_files list(input_path.glob(*.osheet)) def process_file(file_path): try: json_blocks extract_json_blocks(file_path) output_file output_path / f{file_path.stem}.xlsx convert_to_excel(json_blocks, output_file) return f成功转换: {file_path.name} except Exception as e: return f转换失败 {file_path.name}: {str(e)} with ThreadPoolExecutor() as executor: results list(executor.map(process_file, osheet_files)) print(\n.join(results))5. 完整脚本与使用示例将以上代码整合最终脚本如下# osheet_converter.py import json from pathlib import Path import xlsxwriter from concurrent.futures import ThreadPoolExecutor class OSheetConverter: staticmethod def convert_file(input_path, output_pathNone): 单个文件转换 input_path Path(input_path) if not output_path: output_path input_path.with_suffix(.xlsx) json_blocks OSheetConverter.extract_json_blocks(input_path) OSheetConverter.write_excel(json_blocks, output_path) return output_path staticmethod def batch_convert(input_folder, output_folder): 批量转换 input_path Path(input_folder) output_path Path(output_folder) output_path.mkdir(exist_okTrue) osheet_files list(input_path.glob(*.osheet)) with ThreadPoolExecutor() as executor: tasks { executor.submit( OSheetConverter.convert_file, file_path, output_path / f{file_path.stem}.xlsx ): file_path for file_path in osheet_files } for future in tasks: file_path tasks[future] try: output_file future.result() print(f转换成功: {file_path.name} - {output_file.name}) except Exception as e: print(f转换失败 {file_path.name}: {str(e)}) staticmethod def extract_json_blocks(file_path): 提取JSON数据块 with open(file_path, rb) as f: content f.read() json_blocks [] stack [] start_index 0 for i, byte in enumerate(content): if byte 123: # { if not stack: start_index i stack.append(byte) elif byte 125: # } if stack: stack.pop() if not stack: try: json_str content[start_index:i1].decode(utf-8) json.loads(json_str) # 验证 json_blocks.append(json_str) except (UnicodeDecodeError, json.JSONDecodeError): continue return json_blocks staticmethod def write_excel(json_blocks, output_path): 写入Excel文件 workbook xlsxwriter.Workbook(output_path) # 提取工作表信息 sheets_info {} for block in json_blocks: data json.loads(block) if sheets in data: sheets_info data[sheets] # 写入单元格数据 for block in json_blocks: data json.loads(block) if cells in data: sheet_id next((k for k in data.keys() if k.startswith(sh_)), None) if sheet_id and sheet_id in sheets_info: sheet_name sheets_info[sheet_id][title] worksheet workbook.add_worksheet(sheet_name) for row_num, row_data in data[cells].items(): for col_num, cell_data in row_data.items(): worksheet.write(int(row_num), int(col_num), cell_data[v]) workbook.close() if __name__ __main__: import argparse parser argparse.ArgumentParser(description群晖osheet文件转换工具) parser.add_argument(input, help输入文件或文件夹路径) parser.add_argument(-o, --output, help输出文件或文件夹路径) args parser.parse_args() input_path Path(args.input) if input_path.is_file(): output_path args.output if args.output else None OSheetConverter.convert_file(input_path, output_path) elif input_path.is_dir(): output_folder args.output if args.output else converted OSheetConverter.batch_convert(input_path, output_folder)使用示例# 转换单个文件 python osheet_converter.py 文档1.osheet # 批量转换文件夹 python osheet_converter.py /path/to/osheets/ -o /path/to/excels/6. 高级功能扩展基础版本已经能满足大多数需求但我们可以进一步优化6.1 保留基本格式def write_excel(json_blocks, output_path): # ...原有代码... # 添加样式处理 cell_formats {} for block in json_blocks: data json.loads(block) if styles in data: for style in data[styles]: fmt workbook.add_format() if font in style: fmt.set_font_name(style[font]) if size in style: fmt.set_font_size(style[size]) cell_formats[style[id]] fmt # 在写入单元格时应用样式 if cell_format_id in cell_data: worksheet.write(int(row_num), int(col_num), cell_data[v], cell_formats[cell_format_id])6.2 错误处理增强def safe_convert(file_path, output_path): try: json_blocks extract_json_blocks(file_path) if not json_blocks: raise ValueError(未找到有效的JSON数据) write_excel(json_blocks, output_path) return True except Exception as e: error_log Path(output_path).parent / conversion_errors.log with open(error_log, a) as f: f.write(f{time.ctime()} | {file_path.name} | {str(e)}\n) return False6.3 性能优化技巧对于大型文件处理使用mmap内存映射读取大文件限制并发线程数避免内存溢出添加进度显示import mmap def extract_large_file(file_path): with open(file_path, rb) as f: with mmap.mmap(f.fileno(), 0, accessmmap.ACCESS_READ) as mm: # 处理逻辑相同7. 实际应用建议在群晖NAS环境中你可以这样部署这个解决方案定时自动转换设置计划任务监控特定文件夹的新增.osheet文件与Drive客户端集成通过inotify监控文件变化触发自动转换Web界面扩展使用Flask/Django开发简单管理界面常见问题处理问题现象可能原因解决方案转换后内容乱码文件编码问题尝试不同的编码格式丢失部分数据JSON解析不完整检查大括号匹配逻辑性能缓慢文件过大启用内存映射优化这个脚本经过实际测试能够处理大多数.osheet文件转换需求。对于特别复杂的表格如包含合并单元格、数据验证等高级功能可能需要额外处理逻辑。

更多文章