outputStream(輸出流)轉inputstream(輸入流)以及輸入流如何複用

琴声清幽發表於2024-03-23

https://blog.csdn.net/xuxu_study/article/details/129992752


檔案、流之間的轉換
MultipartFile 轉 inputstream(輸入流)
outputStream(輸出流)轉為 inputstream(輸入流)
inputstream (輸入流)轉 ByteArrayOutputStream
MultipartFile 檔案直接轉輸入流上傳和生成摘要
MultipartFile 檔案需要轉為pdf 再進行上傳和生成摘要
檔案上傳原始碼
檔案hash 摘要演算法
docx或doc轉pdf
檔案上傳
需求:
透過MultipartFile 上傳檔案到檔案伺服器,上傳前要把檔案轉為pdf格式進行上傳,並生成檔案摘要用來驗證伺服器中的檔案是否被篡改。

準備:
需要涉及到 inputstream(輸入流)或outputStream(輸出流)要使用兩次 。
一、如果該檔案本身就是pdf格式則直接進行上傳。第一次是透過輸入流去上傳檔案;第二次是透過輸入流去生成檔案摘要。

二、如果該檔案不是pdf則需要工具類把檔案轉為pdf再上傳。轉pdf的工具類 返回的為outputStream(輸出流)。上傳的工具類以及生成摘要的工具類則需要inputstream(輸入流)。
則需要把輸出流進行轉化變為輸入流,然後再第一次是透過輸入流去上傳檔案;第二次是透過輸入流去生成檔案摘要

注:流讀過一次就不能再讀了,而InputStream物件本身不能複製

檔案、流之間的轉換
MultipartFile 轉 inputstream(輸入流)
byte [] byteArr=file.getBytes();
InputStream inputStream = new ByteArrayInputStream(byteArr);
1
2
outputStream(輸出流)轉為 inputstream(輸入流)
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
InputStream inputStream2 = new ByteArrayInputStream(outputStream.toByteArray());
1
2
inputstream (輸入流)轉 ByteArrayOutputStream
//InputStream 轉 ByteArrayOutputStream
//獲取到一個inputstream後,可能要多次利用它進行read的操作。由於流讀過一次就不能再讀了,而InputStream物件本身不能複製,而且它也沒有實現Cloneable介面
public static ByteArrayOutputStream cloneInputStream(InputStream input) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
while ((len = input.read(buffer)) > -1) {
baos.write(buffer, 0, len);
}
baos.flush();
return baos;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}


17
MultipartFile 檔案直接轉輸入流上傳和生成摘要
透過file 轉位元組陣列,因為流不能重複讀,所以要new成兩個輸入流。

//獲取並生成以pdf為字尾的檔名稱
String fileName = StringUtils.substringBeforeLast(originalFilename,".");
fileName = fileName +".pdf";
//如果上傳的為pdf 則直接進行上傳 不需要轉換
if(originalFilename.endsWith(".pdf")){
//檔案轉位元組陣列
byte [] byteArr=file.getBytes();
//輸入流1
InputStream inputStream = new ByteArrayInputStream(byteArr);
//輸入流2
InputStream inputStream2 = new ByteArrayInputStream(byteArr);
//檔案上傳
url = CephUtils.uploadInputStreamReturnUrl("/" + Constants.CEPH_BUCK_NAME, fileName, inputStream);
//生成文件hash 摘要
hash = FileHahUtil.hashAbstractByInputStream(inputStream2);
}


MultipartFile 檔案需要轉為pdf 再進行上傳和生成摘要
//轉換為pdf 後的輸出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//原檔案
byte [] byteArr=file.getBytes();
InputStream inputStream = new ByteArrayInputStream(byteArr);
//要轉為pdf 文件
Word2PdfUtil.convert2PdfStream(inputStream,outputStream);
//輸出流轉輸入流
ByteArrayOutputStream baosPdf = (ByteArrayOutputStream) outputStream ;
InputStream inputStream2 = new ByteArrayInputStream(baosPdf.toByteArray());
//inputStream 只能用來讀取一次 所以進行copy一個新的 用來生成摘要
InputStream inputStream3 = new ByteArrayInputStream(baosPdf.toByteArray());
//生成文件hash 摘要
hash = FileHahUtil.hashAbstractByInputStream(inputStream3);
//上傳檔案
url = fileService.uploadFileByInputStream(inputStream2,fileName);

檔案上傳原始碼
//檔案上傳(文件轉pdf)
@ApiOperation(value = "檔案上傳(文件轉pdf)", produces = "application/json")
@ApiResponses(value = {@ApiResponse(code = 200, message = "檔案上傳(文件轉pdf)")})
@PostMapping(value = "/uploadWordFile")
public BaseVo<Contract> uploadWordFile(HttpServletRequest request, MultipartFile file, HttpServletResponse response){
long startTimeTotal = System.currentTimeMillis();
BaseVo<Contract> baseVo = new BaseVo<Contract>();
baseVo.setCodeMessage(CodeConstant.FAILURE_CODE);
try {
if(null != file){
String originalFilename = file.getOriginalFilename();
//檔案上傳後返回的地址
String url = "";
//檔案摘要的hash值
String hash = "";
if (!originalFilename.endsWith(".docx") && !originalFilename.endsWith(".doc") && !originalFilename.endsWith(".pdf")) {
//上傳的檔案格式不支援
baseVo.setMessage("暫不支援當前檔案格式上傳!");
}else {
//生成新的檔名稱
String fileName = StringUtils.substringBeforeLast(originalFilename,".");
fileName = fileName +".pdf";
//如果上傳的為pdf 則直接進行上傳 不需要轉換
if(originalFilename.endsWith(".pdf")){
byte [] byteArr=file.getBytes();
InputStream inputStream = new ByteArrayInputStream(byteArr);
InputStream inputStream2 = new ByteArrayInputStream(byteArr);
url = CephUtils.uploadInputStreamReturnUrl("/" + Constants.CEPH_BUCK_NAME, fileName, inputStream);
//生成文件hash 摘要
hash = FileHahUtil.hashAbstractByInputStream(inputStream2);
}else {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte [] byteArr=file.getBytes();
InputStream inputStream = new ByteArrayInputStream(byteArr);
//要轉為pdf 文件
Word2PdfUtil.convert2PdfStream(inputStream,outputStream);
ByteArrayOutputStream baosPdf = (ByteArrayOutputStream) outputStream ;
InputStream inputStream2 = new ByteArrayInputStream(baosPdf.toByteArray());
//inputStream 只能用來讀取一次 所以進行copy一個新的 用來生成摘要
InputStream inputStream3 = new ByteArrayInputStream(baosPdf.toByteArray());
//生成文件hash 摘要
hash = FileHahUtil.hashAbstractByInputStream(inputStream3);
url = fileService.uploadFileByInputStream(inputStream2,fileName);
baosPdf.close();
inputStream2.close();
outputStream.close();
}
if(StringUtils.isNotEmpty(url)){
// 儲存合同資訊 到資料庫
Contract contract = new Contract();
//隨機字串
String str = StringUtils.replace(UUID.randomUUID().toString(), "-", "");
contract.setCode(CodeGenerator.getLongCode(str));
contract.setContractUrl(url);
contract.setName(fileName);
contract.setHashCode(hash);
contractService.saveOrUpdate(contract);
//返回合同資訊
baseVo.setData(contract);
baseVo.setCodeMessage(CodeConstant.SUCCESS_CODE);
}
}

}
}catch (Exception e){
e.printStackTrace();
MeUtils.info("uploadFile error",e);
}
long endTimeTotal = System.currentTimeMillis();
MeUtils.info("uploadFile total time:" + (endTimeTotal - startTimeTotal));
return baseVo;
}


生成檔案摘要用的是檔案hash 摘要演算法中的SHA-256,docx或doc轉pdf用的是aspose 中提供的方法,檔案上傳用的Ceph分散式檔案系統中的。這裡暫時不詳細介紹,只貼一些程式碼。後面再出詳細文件,以及開發中遇到的坑。

檔案hash 摘要演算法
/**
* 生成檔案hashCode值
*/
public static String hashAbstractByInputStream(InputStream fis) throws Exception {
String sha256 = null;
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte buffer[] = new byte[1024];
int length = -1;
while ((length = fis.read(buffer, 0, 1024)) != -1) {
md.update(buffer, 0, length);
}
byte[] digest = md.digest();
sha256 = byte2hexLower(digest);
} catch (Exception e) {
e.printStackTrace();
throw new Exception("生成檔案hash值失敗");
} finally {
try {
if (fis != null) {
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return sha256;
}


docx或doc轉pdf
public static void convert2PdfStream(InputStream inputStream, ByteArrayOutputStream outputStream) {
if (!getLicense()) { // 驗證License 若不驗證則轉化出的pdf文件會有水印產生
return;
}
try {
long old = System.currentTimeMillis();
Document doc = new Document(inputStream);
//insertWatermarkText(doc, "測試水印"); //新增水印
PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
pdfSaveOptions.setSaveFormat(SaveFormat.PDF);
// 設定3級doc書籤需要儲存到pdf的heading中
pdfSaveOptions.getOutlineOptions().setHeadingsOutlineLevels(3);
// 設定pdf中預設展開1級
pdfSaveOptions.getOutlineOptions().setExpandedOutlineLevels(1);
//doc.save(outputStream, pdfSaveOptions);
// 全面支援DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,EPUB, XPS, SWF 相互轉換
doc.save(outputStream, SaveFormat.PDF);
long now = System.currentTimeMillis();
System.out.println("共耗時:" + ((now - old) / 1000.0) + "秒"); // 轉化用時

} catch (Exception e) {
e.printStackTrace();
}
}


檔案上傳
/**
* 上傳InputStream檔案
*
* @param bucketName
* @param fileName
* @param input
*/
public static String uploadInputStreamReturnUrl(String bucketName, String fileName, InputStream input) {
// String path = bucketName + timeSuffix();
PutObjectResult putObjectResult = conn.putObject(bucketName, fileName, input, new ObjectMetadata());
String cephUrl = ENDPOINT + bucketName + "/" + fileName;
return cephUrl;
}

文章知識點與官方知識檔案匹配,可進一步學習相關知識
Java技能樹首頁概覽142764 人正在系統學習中
————————————————

版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。

原文連結:https://blog.csdn.net/xuxu_study/article/details/129992752

相關文章