使用electron-vue+go写一个处理excel表格小软件(2)

2023-05-16

目录

  • 问题
  • 思路
  • go部分
    • 主要流程
    • 遇到的坑
  • node部分
    • 主要流程
    • 遇到的坑
  • 源码链接

问题

使用node-xlsx处理excel一次最多能处理30M的文件,所以来个80M的话就要手动拆成3个文件,这看起来太蠢了,需要换一个能处理大excel文件的库。将界面优化成这样子:
在这里插入图片描述

思路

经过测试,js最受欢迎的库js-xlsx也不能处理80M的excel文件,所以可能需要使用另外一种语言的库,如果使用另外一种语言,需要考虑怎么选语言,上手难度,开发成本,还有就是是否能嵌入到electron的桌面应用里,如果能嵌入,该怎么进行数据通信等等问题。

  1. 在electron里支持用node开辟一个子进程去运行其他语言打包出来的可执行文件,这样子就可以实现electron里跑其他语言写的程序
  2. 经过了解,python和go都比较容易上手,而且python有xlsxWriter库,go有excelize库都可以处理超大的excel文件,都是解析出来一个数组,后面处理数组就行。 因为python是解释型语言,打包成可执行文件时会连解释器一起打包,所以就算只写了几行代码,打包出来的包也会是几百兆,go是编译型语言,编译打包出来的包比较小,嵌入electron以后比较轻量,所以选用了go语言
  3. 因为还不熟悉新语言语法,所以做一个tcp的socket通信,将go进程解析出来的数组传到node进程,处理数组生成文件部分就可以用之前写好的node部分逻辑进行处理了
  4. 之前node进程里只处理了生成文件,如果需要用go的excelize库生成excel格式的话还需要将放置生成文件的文件夹路径返回给go进程,go再批量处理excel文件格式

go部分

主要流程

  1. 创建一个tcp的socket
func createServer() {
	// 建立socket,监听端口  第一步:绑定端口
	netListen, err := net.Listen("tcp", "127.0.0.1:9800")
	CheckError(err)
	// defer延迟关闭改资源,以免引起内存泄漏
	defer netListen.Close()

	Log("Waiting for clients")
	for {
		conn, err := netListen.Accept() // 第二步:获取连接
		if err != nil {
			continue // 出错退出当前一次循环
		}

		Log(conn.RemoteAddr().String(), " tcp connect success")
		// 这句代码的前面加上一个 go,就可以让服务器并发处理不同的Client发来的请求
		go handleConnection(conn) // 使用goroutine来处理用户的请求
	}
}
func handleConnection(conn net.Conn) {
	buffer := make([]byte, 2048)
	for { // 无限循环
		n, err := conn.Read(buffer) // 第三步:读取从该端口传来的内容
		words := "ok"               // 向链接中写数据
		conn.Write([]byte(words))
		if err != nil {
			Log(conn.RemoteAddr().String(), " connection error: ", err)
			return // 出错后返回
		}
		tcpData := string(buffer[:n]) // 接收到的数据
	}
}
  1. 接收待处理excel文件的绝对路径,返回解析出来的数组给node进程处理并生成拆分好的excel文件
  2. 接收放置输出文件的文件夹绝对路径,批量处理里面的excel文件格式

遇到的坑

  1. go一些库比较新的版本需要在https://pkg.go.dev/搜,在github里直接搜名字可能搜不到想要的版本链接,比如excelize这个库,直接在github搜是找不到v2的链接的
  2. 静态语言写起来比动态语言麻烦挺多,走到哪一步都是需要确定类型的
  3. 在和node进程通信的时候要适当地加time.Sleep(),不然调用conn.Write()的时候会使本来应该两次传递的消息变成了一次

node部分

主要流程

  1. 在electron的主进程里开辟一个子进程来运行go程序
const isWin = /^win/.test(process.platform)
console.log(process.platform)
const path = require('path')

let pyProc = null

const createPyProc = () => {
  let port = '4242'
  let script = path.resolve(__dirname, 'go', isWin ? 'testGo.exe' : 'testGo')
  if (process.env.NODE_ENV === 'production') {
    script = path.join(process.resourcesPath, 'app.asar.unpacked/go', isWin ? 'testGo.exe' : 'testGo')
  }
  console.log(script)
  pyProc = require('child_process').execFile(script, [port]) // 开辟一个子进程运行go打包出来的可执行程序
  if (pyProc != null) {
    console.log('child process success')
  }
}

const exitPyProc = () => {
  pyProc.kill()
  pyProc = null
}

app.on('ready', createPyProc)
app.on('will-quit', exitPyProc)
  1. 在界面点击开始处理后,开始与go进程进行tcp通信
async () => { 
	let tcpData = ''
	const client = net.connect({ port: 9800 })
	client.write(JSON.stringify(this.sourcePathList))
	client.on('data', async data => {
	  tcpData += data.toString()
	  if (tcpData.startsWith('[')) {
	    // 第一个通信会回抛数组
	    if (tcpData.endsWith('数据传输结束标记')) {
	      data = JSON.parse(tcpData.replace(/数据传输结束标记$/, ''))
	      for (let i = 0; i < data.length; i++) { // 遍历循环用node处理每个表的数据,拆分并生成文件
	        await splitXlsx(
	          data[i],
	          i + 1,
	          data.length,
	          this.folderPath,
	          this.log,
	          this.sourcePathList.length
	        ).catch(e => {
	          this.log.error = e
	          this.isLoading = false
	        })
	      }
	      tcpData = ''
	      // 处理完以后,传文件夹过去给go批量生成xlsx格式
	      client.write(this.folderPath)
	    }
	  } else {
	    // 之后的通信都是回抛处理状态
	    if (tcpData.startsWith('处理中断')) {
	      this.log.error = tcpData
	      this.isLoading = false
	    } else {
	      this.log.text = tcpData
	      if (this.log.text.startsWith('处理结束')) {
	        this.isLoading = false
	      }
	    }
	    tcpData = ''
	  }
	})
}
  1. 待处理文件绝对路径传给go进程,go进程解析出一个大数组后传回给node进程处理拆分数组并循环生成新的excel文件,最终将输出文件所在文件夹绝对路径传给go进程,go进程批量处理excel文件的样式格式和打印格式

遇到的坑

  1. 因为需要运行在win和mac系统,所以需要根据系统环境来选择go的可执行程序文件
  2. 在打包electron安装包的时候,需要将go的可执行程序文件打包进去,我用的是electron-builder打包,需要在package.json里增加打包配置项
    "build": {
        // ...
        "extraResources": [
          {
            "from": "src/main/go", // go文件夹里有go的可执行程序文件
            "to": "app.asar.unpacked/go"
          }
        ],
        // ...
     }
    
    这样子就相当于直接复制这些不需打包的静态文件去到安装包里的app.asar.unpacked文件夹里面,在生产环境取文件路径时可以这样取
     if (process.env.NODE_ENV === 'production') {
        script = path.join(process.resourcesPath, 'app.asar.unpacked/go', isWin ? 'testGo.exe' : 'testGo')
      }
    
    win/mac系统都是可以这样配置的
  3. 由于go是解析完全部80M的文件,解析出来的数组超级大,在tcp中传数据缓冲区会不够用,所以数据变成分块传输,这样node进程就无法确定数据传输完毕的时机,需要在go进程传输的数据上加上结束标识,这样在node进程就需要自己拼接分块传输的数据,并且识别结束标识。
  4. 在excel中的时间戳和js计算出来的时间戳是不一样的
    两者的换算公式如下:
    js时间戳转excel时间戳
    const  excelTimeNum = (Number(new Date()) / 1000 + 8 * 3600) / 86400 + 70 * 365 + 19
    
    excel时间戳转js时间戳
    const jsTimeNum = new Date(((excelTimeNum - 19 - 70 * 365) * 86400 - 8 * 3600) * 1000)
    

源码链接

electron部分
go部分

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用electron-vue+go写一个处理excel表格小软件(2) 的相关文章

  • Java高级特性反射与动态代理模式

    文章目录 前言一 了解反射二 继续了解反射 xff08 哈哈哈 xff09 1 每一个类对应的class放在哪里 xff1f 2 这个class里面都保存了什么3 如何使用 xff1f 3 1 获取类加载器3 2 获取构造器对象3 3 获取
  • Unity3D 使用SceneManager跳转/加载场景

    很久没有更新博客了 xff0c 最近也是还在学习U3D 下面写一下使用SceneManager跳转 加载场景 我们假设要点击一个按钮跳转 xff0c 那么我们只要把跳转的代码写进按钮点击事件里就好了 其实加载场景很简单 xff0c 只需要写
  • Hisat2 Bowtie2比对结果解读

    Bowtie的中文意思是 xff1a 领结 xff0c 蝴蝶结 Bowtie2用户手册 xff1a http bowtie bio sourceforge net bowtie2 manual shtml 在看比对结果前需要了解三个概念 x
  • React 项目启动报错:The “path” argument must be of type string

    今天下载一个旧的React项目 xff0c yarn start 运行 xff0c 报错 xff1a TypeError ERR INVALID ARG TYPE The path argument must be of type stri
  • Android 身份认证基本概念

    身份验证 Android 采用通过用户身份验证把关的加密密钥机制 xff0c 该机制需要以下组件 xff1a 加密密钥存储和服务提供程序 存储加密密钥并基于这些密钥提供标准加密例程 Android 支持由硬件支持的密钥库和 Keymaste
  • Gnome增加消息提醒extension 适用于聊天工具如xchat "message notifier" "notifications alert" "permanent notification&quo

    使用如xchat这样的聊天工具 xff0c 有人跟你说话时 xff0c 在KDE桌面中 xff0c 默认系统托盘中的xchat托盘会闪烁 xff0c 直到你点击将xchat切换到前台 xff0c 这是xchat在preference可以设置
  • 读取文件报错:FileNotFoundError: [Errno 2] No such file or directory

    文章目录 问题描述问题分析解决办法 问题描述 使用 img 61 Image open 39 data DSC 8923 jpg 39 读取一张图片时 xff0c 报 FileNotFoundError Errno 2 No such fi
  • CentOS7离线安装图像化界面踩坑及脱坑历程

    CentOS7离线安装图像化界面 背景安装问题尝试一 xff1a 尝试二 xff1a 其他问题总结 背景 很久之前实验室的一台服务器安装了CentOS 7 6 1810版本的linux系统 xff0c 然而当时安装系统的同学不知出于什么目的
  • Eslint 配置及规则说明

    中文官方网站 基本使用教程 安装 可以全局安装 xff0c 也可以在项目下面安装 如下是在项目中安装示例 xff0c 只需要在 package json 中添加如下配置 xff0c 并进行安装 xff1a gt 34 eslint 34 3
  • Ubuntu自动登录图形系统界面(免密码、开机自启动)

    Ubuntu自动登录图形系统界面 xff08 免密码 开机自启动 xff09 操作系统版本 xff1a 18 04 修改50 unity greeter conf xff0c 使其允许root登录 span class token func
  • 学C++有多难,你知道吗?

    都2020年了 xff0c 还要学C 43 43 吗 xff1f C 43 43 好多理工科大学里面都有 xff0c 它的学习难度比其他编程语言比如Python Javascript 和Java等等难 那为什么呢 xff1f C 43 43
  • 搞懂Java高级特性--注解

    1 注解是什么 xff1f Java注解 xff08 Annotation xff09 又称Java标注 xff0c 是JDK5 0引入的一种注释机制 xff0c 注解是元数据的一种形式 xff0c 提供有关于程序但不属于程序本身的数据 x
  • 为什么都说代码改变世界?是因为这五位程序员创造了未来!

    致敬那些为软件开发奠定坚实基础的计算机科学先驱 从 1 和 0 开始 xff0c 编程经历了很长一段路 xff0c 才达到了现在的抽象状态 过去的程序员用伟大的发明 xff0c 为现代程序员轻松地完成工作奠定了坚实的基础 如果我们研究某个软
  • 编译提示缺少libjli.so,jar command not found,javadoc错误等

    这周一周忙于Ubuntu server环境下的Android编译环境的搭建 xff0c 由于刚开始真正使用Linux xff0c xff08 以前虽然用过Ubuntu xff0c 但是就当win用了 就这样还没坚持下来 xff0c 现在工作
  • 银河麒麟系统4.0.2离线安装MySQL教程

    银河麒麟系统4 0 2离线安装MySQL教程 xff08 Ubuntu离线安装MySQL教程 xff09 https www jianshu com p 478dc7c9b9e0 这个教程很详细 xff0c 我不再多说 xff0c 而且亲测
  • 实现线程同步的几种方式

    在多线程中线程的执行顺序是依靠哪个线程先获得到CUP的执行权谁就先执行 xff0c 虽然说可以通过线程的优先权进行设置 xff0c 但是他只是获取CUP执行权的概率高点 xff0c 但是也不一定必须先执行 在这种情况下如何保证线程按照一定的
  • STC开天斧虚拟示波器使用

    开天斧外观图 xff0c 颜值非常可以 1 在keil中添加STC8H8K64U的型号和头文件 xff0c 添加功能在STC IPS软件里 首先点击Keil仿真设置 xff0c 然后选择单片机型号STC8H8K64U xff0c 然后点击添
  • android AlertDialog 弹窗自定义布局 点击外部不关闭弹窗

    AlertDialog span class token punctuation span Builder builder span class token operator 61 span span class token keyword
  • delete释放new[] 以及 delete[]释放new 的问题

    在同花顺 的笔试过程中遇到这么一个类似问题 A ptr 61 new A 10 for int i 61 0 i lt n i 43 43 delete amp ptr i 由此衍生出两个问题 new 申请的空间用delete释放会发生什么
  • C#中的readonly与const区别

    xfeff xfeff const 的概念就是一个包含不能修改的值的变量 常数表达式是在编译时可被完全计算的表达式 因此不能从一个变量中提取的值来初始化常量 如果 const int a 61 b 43 1 b是一个变量 xff0c 显然不

随机推荐

  • 改变无线连接、有线连接的优先级

    有线和无线连的是同一个网络 xff0c 当笔记本打开时 xff0c 总是优先使用无线连接 xff0c 如何转变优先级为有线连接呢 xff1f 1 打开网络和共享中心 2 更改适配器设置 xff0c 打开网络连接窗口 3 单击此窗口的高级菜单
  • 杂感一

    从2014年7月工作至今已有快2年了 xff0c csdn的博客从毕业后就很少上了 工作中有很多收获 技术上 也在不断积累和成长中 不管做什么事情 xff0c 要坚持下去 xff0c 方得初心 xff0c 把坚持养成习惯 xff0c 学习如
  • Kotlin实战---Retrofit网络模型

    没有Kotlin基础的小伙伴先进这里 Koltin基础文章 1 Java和Kotlin互相调用之间的注意事项 1 解决关键字冲突 span class token keyword public span span class token k
  • MFC隐藏主窗口的方法

    隐藏基于对话框的MFC应用程序窗口的方法 推荐这个方法 xff0c 非常好用 很多人可能会将窗口创建出来 然后用一个 ShowWindow SW HIDE 的方法去隐藏窗口 当然这是可以做到隐藏的功能 但是有一点不足的地方就是窗口在隐藏之前
  • JSP 通过Servlet将excel数据导入SQL

    1 gt 在网上下载jxl jar 这个JAR包用于Java操作excel 下载后 xff0c 将这个包复制到工程Webroot下的WEB INF下的lib中 xff0c 或是在工程中导入jxl jar包 2 gt 准备excel文件 如图
  • 1=5,2=15,3=215,4=2145,那么5=?

    如题 xff0c 1 61 5 xff0c 2 61 15 xff0c 3 61 215 xff0c 4 61 2145 xff0c 那么5 61 xff1f 答案 xff1a 5 61 1 哎 xff0c 这个题出的 xff0c 没反应过
  • 村子里有50个人,每人有一条狗,在这50条狗中有病狗(这种病不传染),于是人们要找出病狗。

    xff29 xff22 xff2d 公司向来以高素质人才作为企业持续竞争力的保证 进入 xff29 xff22 xff2d 公司是差不多每个 xff29 xff34 人的梦想 下面这条 xff29 xff22 xff2d 公司的面试题 xf
  • 删除单向链表中的某一个节点

    已知一个单向链表的表头head xff0c 写出一个删除某一个节点的算法 xff0c 要求先找到此节点 xff0c 然后删除 include lt iostream gt using namespace std typedef struct
  • 多段图的最短路径问题-----动态规划法

    对多段图 xff0c 求最短路径 xff0c 如图 xff1a 对其使用动态规划法 xff1a 阶段 xff1a 将图中的顶点划分5个阶段 xff0c k 状态 xff1a 每个阶段有几种供选择的点s 决策 xff1a 当前状态应在前一个状
  • Android 文件存储 和 权限管理

    转载请标明出处 xff1a xff1a http blog csdn net huaiyiheyuan article details 52473984 android SD卡主要有两种存储方式 Internal External Stor
  • Python 连接Linux服务器完成上传下载和执行命令及查询目录下的文件

    Python 连接Linux服务器完成上传下载和执行命令及查询目录下的文件 记录一些用于连接linux获取远端文件或者上传文件的小工具 xff0c 另外还有执行shell命令和查找linux目录下文件是否存在 span class toke
  • 【学习整理】Windows server 2019AD域之创建用户的三种形式

    内置工具程序csvde exe xff0c ldifde exe dsadd exe csvde exe xff1a 能利用它来新建用户账户 xff0c 但不能修改 需要将用户数据输入纯文本文件中ldifde exe xff1a 可以利用它
  • 邮件退信提示

    一般情况下 xff0c 当您发送的邮件无法正常到达收件人时 xff0c winmail 邮件系统将会自动给您发一封系统退信 xff0c 这封退信通知里面包含了无法正常发送到对方邮件地址的原因 xff0c 所以绝大多数情况下可以通过退信通知来
  • 学以致用--注解加反射实现Butterknife的View注入功能

    不知不觉更文挑战来到了第三天 xff0c 今天来写一篇反射和注解的应用篇 对反射不熟悉的同学 xff0c 请阅读 搞懂Java反射和JDK里的动态代理 对注解不熟悉的同学 xff0c 请阅读 搞懂Java高级特性 注解 首先这篇文章 xff
  • 百度试题---开发测试工程师

    一 问答题 说出常用的几种希哈函数 xff0c 其作用是什么 xff1f 描述OSI 的七层网络结构 xff0c HTTP 工作在哪一层 xff1f 描述一段C 语言代码程序能运行起来的代码要求和执行过程 二 算法设计 有一车苹果 xff0
  • 错误: Entry在LinkedHashMap中不是公共的; 无法从外部程序包中对其进行访问

    遇到了一个很奇怪的问题 xff0c 使用LinkedHashMap来做LRU缓存时 xff0c 重写protected boolean removeEldestEntry Entry lt String String gt eldest 方
  • 【安卓真机调试】较全面的Android真机调试详解

    目录 1 启动调试功能1 1 配置设备上的开发者选项1 2 运行可调试的 build 变体 2 开始调试2 1 设置断点2 2 选择设备2 3 在工具栏中点击Debug图标2 4 打开Debug窗口2 5 将调试程序连接到正在运行的应用上
  • 如何搭建ftp服务器实现文件共享

    这里以windows系统和linux系统为例 xff0c 简单介绍一下如何在这2种系统下搭建ftp服务器 xff0c 整个过程非常简单 xff0c 感兴趣的朋友可以自己尝试一下 xff1a windows windows系统自带有ftp服务
  • Rabbitmq—— 从入门到放弃

    文章目录 背景总体架构类与方法BlockingConnection init channel BlockingChannelqueue declarequeue deleteexchange declarebasic publishbasi
  • 使用electron-vue+go写一个处理excel表格小软件(2)

    目录 问题思路go部分主要流程遇到的坑 node部分主要流程遇到的坑 源码链接 问题 使用node xlsx处理excel一次最多能处理30M的文件 xff0c 所以来个80M的话就要手动拆成3个文件 xff0c 这看起来太蠢了 xff0c