使用Tika检测Content-Type上传GCS文件损坏,手动设置则正常
问题原因分析
核心问题出在输入流的状态被修改:Apache Tika的detect(InputStream)方法会读取流中的内容来判断文件类型,这会导致流的指针移动到流的末尾。当后续调用Google Cloud Storage SDK的bucket.create方法时,输入流已经没有可读数据,实际上传的是不完整或空的文件内容,因此下载后文件损坏。
虽然控制台显示的文件大小、Content-Type等元数据看似正确,但这是因为SDK可能提前获取了流的长度(比如针对文件流时读取文件系统的大小),但实际传输的内容已经缺失。
解决方案
针对这个问题,有几种可行的修复方式,根据你的场景选择:
1. 包装流并重置位置(适合大多数流场景)
如果输入流支持标记/重置(或通过包装使其支持),可以在检测类型后将流重置到初始位置:
Tika tika = new Tika(); // 用BufferedInputStream包装原始流,使其支持mark/reset InputStream bufferedStream = new BufferedInputStream(inputStream); // 标记流的初始位置,参数设为流的最大可能长度 bufferedStream.mark(Integer.MAX_VALUE); String contentType = tika.detect(bufferedStream); System.out.println(contentType); //"application/pdf" // 将流重置到标记的初始位置 bufferedStream.reset(); if("application/pdf".equals(contentType)) { return bucket.create(Utilities.formatDirectoryName(directory) + name, bufferedStream, contentType); } else { System.out.println("INVALID TYPE"); return null; }
2. 将流读取为字节数组(适合小文件场景)
如果文件体积不大,可以先将流内容读取到字节数组中,再分别用于Tika检测和上传:
Tika tika = new Tika(); // 读取流内容到字节数组(可使用Apache Commons IO的IOUtils,或自行实现读取逻辑) byte[] fileBytes = IOUtils.toByteArray(inputStream); String contentType = tika.detect(fileBytes); System.out.println(contentType); //"application/pdf" // 用字节数组重新生成输入流用于上传 if("application/pdf".equals(contentType)) { return bucket.create(Utilities.formatDirectoryName(directory) + name, new ByteArrayInputStream(fileBytes), contentType); } else { System.out.println("INVALID TYPE"); return null; }
3. 直接用文件路径/File对象检测(如果有本地文件)
如果你的原始文件存储在本地磁盘,可以直接使用Tika的detect(File)重载方法,避免操作输入流:
Tika tika = new Tika(); File localFile = new File("你的本地文件路径"); String contentType = tika.detect(localFile); System.out.println(contentType); //"application/pdf" // 重新打开文件流用于上传 try (InputStream fileStream = new FileInputStream(localFile)) { if("application/pdf".equals(contentType)) { return bucket.create(Utilities.formatDirectoryName(directory) + name, fileStream, contentType); } else { System.out.println("INVALID TYPE"); return null; } } catch (IOException e) { // 处理异常 e.printStackTrace(); return null; }
内容的提问来源于stack exchange,提问作者Raymond Holguin
相关产品推荐
相关产品推荐

