【问题标题】:Inline input stream processing in JavaJava中的内联输入流处理
【发布时间】:2016-01-16 00:02:18
【问题描述】:

我需要一些关于以下问题的帮助。我正在做一个需要处理文件的项目。 我从用户那里获得了输入流的句柄,在将其写入磁盘之前,我需要执行某些步骤。

  • 计算文件摘要
  • 检查仅存在 1 个 zip 文件,如果已压缩则解压缩数据
  • dos 2 unix 转换
  • 记录长度验证
  • 并将文件加密并保存到磁盘

如果过程中出现异常也需要断流 我尝试使用管道输出和输入流,但约束是 Java 建议它在 2 个单独的线程中运行。一旦我从输入流中读取,我就无法在其他处理步骤中使用它。文件可能非常大,因此无法缓存缓冲区中的所有数据。 请提供您的建议,或者我可以使用任何第三方库。

【问题讨论】:

    标签: java stream zip inputstream


    【解决方案1】:

    最大的问题是您需要先查看提供的 InputStream 以确定您是否收到了 zipfile。

    private boolean isZipped(InputStream is) throws IOException {
        try {
            return new ZipInputStream(is).getNextEntry() != null;
        } catch (final ZipException ze) {
            return false;
        }
    }
    

    在此之后,您需要在设置 DigestInputStream 之前将输入流重置为初始位置。 然后直接读取 ZipInputstream 或 DigestInputstream。 完成处理后,将 DigestInputStream 读取到最后,以便获取摘要。 下面的代码已通过包装“CountingInputstream”进行验证,该包装跟踪从提供的 FileInputStream 读取的字节总数。

        final FileInputStream fis = new FileInputStream(filename);
        final CountingInputStream countIs = new CountingInputStream(fis);
    
        final boolean isZipped = isZipped(countIs);
    
        // make sure we reset the inputstream before calculating the digest
        fis.getChannel().position(0);
        final DigestInputStream dis = new DigestInputStream(countIs, MessageDigest.getInstance("SHA-256"));
    
        // decide which inputStream to use
        InputStream is = null;
        ZipInputStream zis = null;
        if (isZipped) {
            zis = new ZipInputStream(dis);
            zis.getNextEntry();
            is = zis;
        } else {
            is = dis;
        }
    
        final File tmpFile = File.createTempFile("Encrypted_", ".tmp");
        final OutputStream os = new CipherOutputStream(new FileOutputStream(tmpFile), obtainCipher());
        try {
            readValidateAndWriteRecords(is, os);
            failIf2ndZipEntryExists(zis);
        } catch (final Exception e) {
            os.close();
            tmpFile.delete();
            throw e;
        }
    
        System.out.println("Digest: " + obtainDigest(dis));
        dis.close();
    
        System.out.println("\nValidating bytes read and calculated digest");
        final DigestInputStream dis2 = new DigestInputStream(new CountingInputStream(new FileInputStream(filename)), MessageDigest.getInstance("SHA-256"));
        System.out.println("Digest: " + obtainDigest(dis2));
        dis2.close();
    

    不是很相关,但这些是辅助方法:

    private String obtainDigest(DigestInputStream dis) throws IOException {
        final byte[] buff = new byte[1024];
        while (dis.read(buff) > 0) {
            dis.read(buff);
        }
        return DatatypeConverter.printBase64Binary(dis.getMessageDigest().digest());
    }
    
    private void readValidateAndWriteRecords(InputStream is, final OutputStream os) throws IOException {
        final BufferedReader br = new BufferedReader(new InputStreamReader(is));
        // do2unix is done automatically by readline
        for (String line = br.readLine(); line != null; line = br.readLine()) {
            // record length validation
            if (line.length() < 1) {
                throw new RuntimeException("RecordLengthValidationFailed");
            }
            os.write((line + "\n").getBytes());
        }
    }
    
    
    private void failIf2ndZipEntryExists(ZipInputStream zis) throws IOException {
        if (zis != null && zis.getNextEntry() != null) {
            throw new RuntimeException("Zip File contains multiple entries");
        }
    }
    

    ==> 输出:

    摘要:jIisvDleAttKiPkyU/hDvbzzottAMn6n7inh4RKxPOc=
    CountingInputStream 关​​闭。读取的总字节数:1100

    验证读取的字节和计算的摘要
    摘要:jIisvDleAttKiPkyU/hDvbzzottAMn6n7inh4RKxPOc=
    CountingInputStream 关​​闭。读取的总字节数:1072

    有趣的问题,我的回答可能太过分了:)

    【讨论】:

    • 感谢您的回答。这很有帮助。同样有没有一种方法可以组合使用dos2unix流而不是手动转换?
    猜你喜欢
    • 1970-01-01
    • 2021-04-24
    • 1970-01-01
    • 2016-10-13
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    相关资源
    最近更新 更多