wangguanquan / eec

A fast and lower memory excel write/read tool.一个非POI底层,支持流式处理的高效且超低内存的Excel读写工具
https://github.com/wangguanquan/eec/wiki
Apache License 2.0
224 stars 58 forks source link

请问如何在Ubuntu里导出xlsx文件时,文件名支持中文 #395

Open zhangwx95 opened 1 month ago

zhangwx95 commented 1 month ago

导出数据的时候报错如下:看着是中文不支持,在windows下没有这个问题,在docker部署的 Ubuntu22.04下 java.nio.file.InvalidPathException: Malformed input or input contains unmappable characters: MO样例1.pcap.xlsx at sun.nio.fs.UnixPath.encode(UnixPath.java:147) at sun.nio.fs.UnixPath.(UnixPath.java:71) at sun.nio.fs.UnixFileSystem.getPath(UnixFileSystem.java:281) at sun.nio.fs.AbstractPath.resolve(AbstractPath.java:53) at org.ttzero.excel.entity.IWorkbookWriter.reMarkPath(IWorkbookWriter.java:104) at org.ttzero.excel.entity.e7.XMLWorkbookWriter.reMarkPath(XMLWorkbookWriter.java:436) at org.ttzero.excel.entity.e7.XMLWorkbookWriter.writeTo(XMLWorkbookWriter.java:118) at org.ttzero.excel.entity.Workbook.writeTo(Workbook.java:680) 打印看系统编码 file.encoding: UTF-8 LANG: zh_CN.UTF-8 LANGUAGE: zh_CN:en_US LC_ALL: zh_CN.UTF-8

业务代码就是在writeTo报错: Workbook wb = new Workbook(fileName); //fileNameb为 MO样例1.pcap.xlsx //数据导出 wb.writeTo(Paths.get(comPath)); 请问这是编码问题吗,要怎么改才能支持中文

wangguanquan commented 1 month ago

我在网上查了一下有挺多这种场景,出问题应该是Paths.get(comPath + "/MO样例1.pcap.xlsx")这一句,你可以尝试独立出这一句来执行并验证,我并没有这样的环境所以无法给出准确的解决办法,以下解决方法可以逐一尝试

  1. 避免使用Paths创建中文路程径,首先Workbook使用无参构造函数,其次将wb.writeTo(Paths.get(comPath));改为wb.writeTo(new File(comPath + "/" + fileName));
  2. 避免创建本地文件,将workbook直接写入输出流wb.writeTo(new FileOutputStream(comPath + "/" + fileName));
zhangwx95 commented 1 month ago

感谢大佬,可以确认就是文件名称带中文导致的,把中文替换掉是ok的,不过提供的两个方法仍然不能正确的显示中文文件名 方法1,报错和之前一样 方法2,报错java.io.FileNotFoundException:,将目录创建后 Path path = Paths.get(comPath); if (!Files.exists(path)) { Files.createDirectories(path); } 文件生成成功,但是中文仍然没被识别,被替换成了下划线 MO__1.pcap.xlsx TAT

wangguanquan commented 1 month ago

方法2是HTTP下载后中文无法被识别吗?如果是这样的话可以设置Response头来解决,直接使用以下代码测试一下

@RequestMapping("/download")
public void download(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String fileName = java.net.URLEncoder.encode("MO样例1.pcap.xlsx", "UTF-8");
    response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"; filename*=utf-8''" + fileName);
    new Workbook().addSheet(new EmptySheet()).writeTo(response.getOutputStream());
}
zhangwx95 commented 1 month ago

方法2是这个意思吗,我理解错了; 我还是通过 wb.writeTo(new FileOutputStream(comPath + encodeFileName)); 生成文件 应该是我的docker镜像有问题,我再看看,谢谢大佬

wangguanquan commented 1 month ago

应该是最初的写法引起误解了,方法2直接写到输出流是为了规避将中文文件名写到本地上,所以直接写入response。你可以尝试一下上面的完整示例代码看一下是否能正常。

即便正常也会有一定问题,上面示例代码只支持同步下载,数据量大的话可能会造成前端页面假死,异步下载的话可以将文件名进行编码或者用ID代替,下载的时候使用这个编码或ID找到实际文件名,然后使用上面的方法直接下载即可。

zhangwx95 commented 1 month ago

谢谢大佬,你给的方法2确实下载没有问题,名称中文都正常

我最后重新在ubuntu22.04上做了个支持中文的镜像,然后启动docker出现了 There is insufficient memory for the Java Runtime Environment to continue.

Cannot create GC thread. Out of system resources.

折腾不出来,最后直接用了--privileged启动docker 就正常启动了,结果文件中文名称也正常

提问的那个版本的docker镜像应该是中文设置没生效导致的,但是也很奇怪只有文件名中文异常,文件里面的sheet名称 文件内容、系统里的log打印中文都正常。。。

不过总之就是docker镜像的问题,重新做一个就好了。。。谢谢大佬