我需要在此代码中手动关闭FileInputStream吗?

时间:2017-02-21 03:16:02

标签: java keystore fileinputstream

我遇到了我的某个应用程序的问题,并在处理涉及打开文件和阅读内容的大量事务时遇到以下异常:

java.io.FileNotFoundException: /keystore-sample/keystore.jks (Too many open files)

我有以下用java编写的示例代码:

try {  
    EncryptDecryptPassword crypt = new EncryptDecryptPassword();
    String secretKey = "secret123";
    String trustpassencrypted = "ecnrypted1234";
    String trustpass = crypt.decryptPassword(trustpassencrypted.trim(), secretKey.trim());

    File truststore = new File("/keystore-sample/keystore.jks");      
    KeyStore keyStore = KeyStore.getInstance("JKS");    
    keyStore.load(new FileInputStream(truststore), trustpass.toCharArray());
    //Continue with the rest of the code...

} catch (KeyStoreException kse) {            
    System.out.println("Security configuration failed with the following: " + kse.getCause());        
} catch (NoSuchAlgorithmException nsa) {            
    System.out.println("Security configuration failed with the following: " + nsa.getCause());        
} catch (FileNotFoundException fnfe) {            
    System.out.println("Security configuration failed with the following: " + fnfe.getCause());        
} catch (UnrecoverableKeyException uke) {            
    System.out.println("Security configuration failed with the following: " + uke.getCause());        
} catch (CertificateException ce) {            
    System.out.println("Security configuration failed with the following: " + ce.getCause());        
}catch (IOException ioe) {            
    System.out.println("Security configuration failed with the following: " + ioe.getCause());        
}

如您所见,我没有为FileInput流声明一个新实例,如下所示
更正:我的目的是表示我没有将新创建的FileInputStream分配给变量并稍后手动关闭它,如下所示:

FileInputStream in = new FileInputStream(truststore);
keyStore.load(in, trustpass.toCharArray());
//once done with the input stream, close it
in.close();

我的问题是:新的FileInputStream(truststore)是否真的需要手动关闭,否则它将由底层Keystore类处理?快速浏览Keystore.class的底层反编译代码,我没有看到。只是为了确认这是否是我遇到异常的特殊原因。

此外,上面的代码实现被认为是不好的做法吗?

修改

由于我正在运行的应用程序环境有一些限制,这是使用旧的Java SE 6u34。

2 个答案:

答案 0 :(得分:3)

  

我没有为FileInput流声明一个新实例

这句话毫无意义。没有“声明新实例”这样的事情。您已经创建一个新实例,您只是没有声明一个引用变量来存储它。这并不能解除您的负担。新实例,或关闭它的责任。

  

我的问题是:新的FileInputStream(truststore)实际上是否需要手动关闭

  

或它将由底层Keystore类处理?

没有

  

快速浏览Keystore.class的底层反编译代码,我没有看到。只是为了确认这是否是我遇到异常的特殊原因。

'打开的文件太多':您正在泄漏文件描述符,无论是在这里还是其他地方。

  

此外,上面的代码实现被认为是不好的做法吗?

是的,因为你根本没有关闭FileInputStream。请注意,在keyStore.load()之后关闭它是不够的,因为这可能会引发异常。

这些天你会使用try-with-resources:

File truststore = new File("/keystore-sample/keystore.jks");      
try (FileInputStream fis = new FileInputStream(truststore))
{
    KeyStore keyStore = KeyStore.getInstance("JKS");    
    keyStore.load(fis, ...);
}

即使有异常也会自动关闭它。

答案 1 :(得分:1)

你没有"声明一个新实例"是无关紧要的 - 关键是你通过new 创建一个实例。理解这一点至关重要 - 即使您没有通过将其分配给变量来保留该实例的句柄,您仍然可以创建它。

一般情况下,如果您创建它,您有责任关闭它。既然你说你不能使用Java 7的try-with-resources,你可以使用在finally块中关闭创建资源的旧模式。

InputStream trust = null;
try {   
    EncryptDecryptPassword crypt = new EncryptDecryptPassword();
    String secretKey = "secret123";
    String trustpassencrypted = "ecnrypted1234";
    String trustpass = crypt.decryptPassword(trustpassencrypted.trim(), secretKey.trim());

    File truststore = new File("/keystore-sample/keystore.jks");      
    KeyStore keyStore = KeyStore.getInstance("JKS");    
    trust = new FileInputStream(truststore)
    keyStore.load(trust, trustpass.toCharArray());
    //Continue with the rest of the code... 
} catch (Exception e) {     
    // note that logging the stack trace is generally a better practice!       
    System.out.println("Security configuration failed with the following: " + e.getCause());        
} finally {
    try { // because close can throw an exception
        if (trust != null) trust.close();
    } catch (IOException ignored) {}
}

此外,由于您在所有例外情况下做同样的事情,列出所有例外情况的唯一原因是,如果您觉得它增加了代码的可读性(个人而言,我不会)通过明确指出您期望的例外情况。或者,再次根据您使用的Java版本,您可以将它们全部列在catch块中,用|分隔。