我正在开发一个在 Apache Tomcat 上运行的网络应用程序。此 webapp 从相机创建图像并将其 base64 编码发送到 Servlet。然后 servlet 应该保存该图像。一切正常,除了当我打开图像时图像显示不完整。我比较了 base64 字符串并注意到,发送的字符串和 Java 打印的字符串之间存在差异。您知道这些差异可能来自何处吗?
区别如下: - Java 字符串更长 - 前 ~7610 个字节相等 - 在第 7610 个字节之后,字符串不同
private Path saveAsFile(InputStream stream) throws IOException {
byte[] bytes = new byte[1024];
String base64String = "";
while (stream.read(bytes) != -1) {
String tmp = new String(bytes, StandardCharsets.UTF_8);
base64String += tmp;
}
//this prints out a longer base64 String than the Javascript part
System.out.println(base64String);
String replaced = base64String.replaceFirst("data:image/png;base64,", "");
byte[] replacedbytes = Base64.decodeBase64(replaced);
Path temp = Files.createTempFile("photo", ".png");
FileOutputStream fos = new FileOutputStream(temp.toFile());
fos.write(replacedbytes);
return temp;
}
提前致谢!
最佳答案
这个:
byte[] bytes = new byte[1024];
String base64String = "";
while (stream.read(bytes) != -1) {
String tmp = new String(bytes, StandardCharsets.UTF_8);
base64String += tmp;
}
不是在 java 中读取流的有效方法。 (基本上,您必须考虑 stream.read() 返回的值作为缓冲区中实际有效的字节数,并使用 new String(bytes, 0, theAboveValue, charset)
作为字符串构造函数。
除此之外,您没有正确关闭 FileOutputStream
。
但即便如此,这里还有其他问题(在连接流之前解码字符集可能是一个等待发生的错误 - 但它会起作用,因为 base64 实际上是纯 ASCII,没有多字节字符会在这里导致错误。纯属运气)。
清理代码的 IO 部分,它应该看起来像:
private Path saveAsFile(InputStream stream) throws IOException {
byte[] bytes = new byte[1024];
int readBytes = 0;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while ((readBytes = stream.read(bytes)) != -1) {
buffer.write(bytes, 0, readBytes);
}
//this prints out a longer base64 String than the Javascript part
String base64String = new String(buffer.getBytes, "US-ASCII");
String replaced = base64String.replaceFirst("data:image/png;base64,", "");
byte[] replacedbytes = Base64.decodeBase64(replaced);
Path temp = Files.createTempFile("photo", ".png");
FileOutputStream fos = new FileOutputStream(temp.toFile());
fos.write(replacedbytes);
fos.close();// You should not miss that too! And put it in a "finally" step not to leak file descriptors.
return temp;
这可能效果更好,但就内存消耗而言是低效的(将字节转换为字符串再转换为字节,每一步都进行复制!)。
有更好的方法!
使用库进行此类复制可能会更好。 Apache Commons IO 和 Commons Codec 有很好的 Base64InputStream
和 IOUtils.copy
类,可以在这里提供帮助。
在这种情况下,它可以读作:
private Path saveAsFile(InputStream stream) throws IOException {
// Maybe you should advance the stream to skip the "data/image stuff"...
//stream.skip(theActualNumberOfBytesToSkip);
try (Base64InputStream decoded = new Base64InputStream(stream); FileOutputStream file = /*whatever*/) {
IOUtils.copy(decoded, file);
}
}
关于java - JS和Java中相同图像的不同Base64字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47350474/