java - JS和Java中相同图像的不同Base64字符串

标签 java file tomcat servlets base64

我正在开发一个在 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 有很好的 Base64InputStreamIOUtils.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/

相关文章:

java - JSTL 除法自动舍入为 1 或 0

java - 如何删除列表中的前 X 条目<Double>

java - 加载父级时急切地获取子级

java - 哪里可以上传Tomcat可以访问的文件?

java - Jersey - Eclipse - Tomcat - 404

java - 在 Java 的排序列表中搜索字符串,并可能搜索以部分字符串开头的所有字符串

c - fscanf c 编程奇怪的错误

无法从 C 中的文本文件中读取所有名称

ruby-on-rails - 在 Rails 中使用回形针进行 ajax 上传的简单方法?

java - 编译错误: org. eclipse.jdt.internal.compiler.classfmt.ClassFormatException