跨操作系统读取Spring Boot WAR中文件,如何获取一致字节数组?
跨操作系统读取WAR包内文件时字节数组不一致的解决方案
场景描述
我有一个以WAR包运行的Spring Boot应用,需在不同操作系统中测试。读取resources目录(WAR内路径为/WEB-INF/classes/file-name)文件的步骤如下:
- 获取输入流:
InputStream fileAsInputStream = new ClassPathResource("file-name").getInputStream(); - 将输入流转换为字节数组:
byte[] fileAsByteArray = IOUtils.toByteArray(fileAsInputStream);
问题现象
不同操作系统下得到的字节数组内容不一致,导致后续SFTP通信操作异常。核心原因是文件中的换行符差异:
- Linux环境下换行符为
\n(十六进制0x0A,十进制10) - Windows环境下换行符为
\r\n(十六进制0x0D 0x0A,十进制13、10)
示例差异:
- Linux环境字节数组:
[114, 115, 97, 10, 69, 110] - Windows环境字节数组:
[114, 115, 97, 13, 10, 69, 110]
文件为SFTP通信的私钥,内容本身一致,但运行操作系统不同导致字节数组差异。尝试用StandardCharsets.UTF_8处理(如下代码),仍无法解决问题:
IOUtils.toByteArray(new BufferedReader(new InputStreamReader(new ClassPathResource("file-name").getInputStream())), StandardCharsets.UTF_8)
目前已有的临时方案是遍历字节数组,将换行符统一映射为相同字节(例如把10替换为13+10),但希望找到更优的解决方案。
最优解决方案
1. 从根源避免:确保WAR包内文件字节一致
直接读取原始字节流本应在任何系统下得到相同结果,若出现差异,大概率是文件在打包或版本控制阶段被修改了换行符。可通过以下方式解决:
- 版本控制设置:在Git的
.gitattributes文件中添加规则,强制私钥文件以二进制方式存储,避免自动转换换行符:file-name binary - 打包工具配置:在Maven/Gradle中关闭资源过滤,防止打包时修改文件内容:
- Maven:在
pom.xml的resources节点中设置<filtering>false</filtering><build> <resources> <resource> <directory>src/main/resources</directory> <filtering>false</filtering> </resource> </resources> </build> - Gradle:在
build.gradle中设置resources的filtering为falsesourceSets { main { resources { filtering = false } } }
- Maven:在
完成上述配置后,直接使用最初的代码读取字节流,即可在任意操作系统下得到一致的结果。
2. 统一转换换行符(若无法保证文件一致性)
如果无法避免文件本身存在换行符差异,可通过字符流读取后统一转换为目标格式,比手动遍历字节数组更简洁高效:
// 读取文件内容为字符串,统一换行符为LF(\n) String content = IOUtils.toString(new ClassPathResource("file-name").getInputStream(), StandardCharsets.UTF_8); // 将CRLF或单独的CR统一替换为LF content = content.replaceAll("\r\n?", "\n"); // 转换为统一的字节数组 byte[] consistentBytes = content.getBytes(StandardCharsets.UTF_8);
3. 关于私钥文件的说明
SSH私钥本质是文本格式,正常情况下换行符差异不会影响其有效性。若你的SFTP客户端对换行符敏感,使用上述统一转换方案即可解决问题。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

