尽量避免诸如x.read(new FileInputStream(sourceFile)); 的写法

本文通过一次意外的调试经历,揭示了在Java中不当使用文件流可能导致的问题。具体讨论了在不正确关闭InputStream的情况下,如何影响文件备份逻辑的正常执行,并提供了解决方案。

      一不小心,顺手写了x.read(new FileInputStream(sourceFile)); 这样的代码,却引得自己花费了半个多小时去调试问题。
     原因是这样的:在开发某一个feature的时候,需要对操作的文件进行backup,于是写了诸如下面的代码(以下仅是演示代码,与实际要简易,仅供参考):

/*
 * XXX是一个处理类,soureFile是一个输入的File object
 
*/

XXX x 
= new XXX();
x.read(
new FileInputStream(sourceFile));
..... 
//complex logic process

String sourceFilePath 
= sourceFile.getPath();
int maxBackups = 3;

List
<File> files = new ArrayList<File>();
files.add(traFile);
String base 
= sourceFile.getPath() + '.';
for (int generations = 1true; generations++) {
    File f 
= new File(base + generations);
    files.add(f);
    
if (!f.exists()) {
        
break;
    }
}

int generations = files.size();
for (int generation = generations - 1; generation > 0; generation--) {
    
if (generation > maxBackups) {
        files.get(generation).delete();
    } 
else {
        
if(files.get(generation).exists()) files.get(generation).delete();
        files.get(generation 
- 1).renameTo(files.get(generation));
    }
}

..... 
//complex logic process
x.write(new FileOutputStream(sourceFilePath));

当写完以后,运行TestCase并不是每次都成功,有时候就可以正确生成backup文件,而有时候则没有生成(没有生成的概率大很多)。跟踪了一下,发现当没有正确生成backup的时候,是那段file renameTo没有执行成功。就是如上面代码中“粗粉红色的标记的”:files.get(generation - 1).renameTo(files.get(generation))

然后进行Debug状态的step by step运行,却每次都成功了。
仔细了想了想,可能的原因是 files.get(generation - 1) 这个所引对象的对象,在执行renameTo操作的时候,可能还在被某个资源锁定,而没有释放。

带着个这个想法,把代码从头再过了一遍,终于发现是 x.read(new FileInputStream(sourceFile)); 这段出了问题。因为XXX这个类,在内部处理过程中,并没有对输入的inputstream进行关闭(当然,这是一个正确的设计和实现,一般我们在开发过程中,都不会在“使用者”内部关闭外部的流,这样危险性非常大)。

但是,为了代码了简洁,很随意的就进行了 x.read(new FileInputStream(sourceFile));  这样的书写

正是这样的书写,让后面针对soureFile的操作不能执行成功。因为所用在这个soureFile上的InputStream流并没有被“真正关闭”。

于是改成:
InputStream is = new FileInputStream(sourceFile);
x.read(is);
is.close;
就可以了。

当然,并不是说诸如 x.read(new FileInputStream(sourceFile));  的写法不能用,而是尽量避免在“在同一个方法开闭区间内多次引用sourceFile”,在这样场合下,就肯定不能用了。




`FileInputStream` 抛出 `java.io.FileNotFoundException` 异常通常是因为指定的文件不存在、路径错误、没有访问权限等原因。以下是解决该异常的方法: #### 1. 检查文件是否存在 在使用 `FileInputStream` 之前,先检查文件是否存在。可以使用 `File` 类的 `exists()` 方法来进行检查。示例代码如下: ```java import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class CheckFileExists { public static void main(String[] args) { File file = new File("path/to/your/file.txt"); if (file.exists()) { try { FileInputStream fis = new FileInputStream(file); // 读取文件操作 int readData = fis.read(); System.out.println(readData); fis.close(); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("文件不存在"); } } } ``` #### 2. 检查文件路径是否正确 确保文件路径是正确的,包括文件名的大小写(在某些系统中,文件名是区分大小写的)。如果使用相对路径,要明确相对的基准目录。示例代码如下: ```java import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class CorrectFilePath { public static void main(String[] args) { try { // 使用绝对路径 FileInputStream fis = new FileInputStream("C:\\your\\absolute\\path\\file.txt"); // 读取文件操作 int readData = fis.read(); System.out.println(readData); fis.close(); } catch (FileNotFoundException e) { System.out.println("文件路径错误或文件不存在"); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } ``` #### 3. 检查文件访问权限 确保程序有足够的权限访问该文件。如果文件位于受保护的目录中,可能需要提升程序的权限。示例代码如下: ```java import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class CheckFilePermission { public static void main(String[] args) { File file = new File("path/to/your/file.txt"); if (file.canRead()) { try { FileInputStream fis = new FileInputStream(file); // 读取文件操作 int readData = fis.read(); System.out.println(readData); fis.close(); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("没有访问文件的权限"); } } } ``` #### 4. 处理特殊字符和转义字符 如果文件路径中包含特殊字符,需要进行正确的转义。例如,在 Java 中,反斜杠 `\` 是转义字符,需要使用双反斜杠 `\\` 来表示一个反斜杠。示例代码如下: ```java import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; public class HandleSpecialCharacters { public static void main(String[] args) { try { // 正确处理反斜杠 FileInputStream fis = new FileInputStream("C:\\your\\path\\with\\special\\characters.txt"); // 读取文件操作 int readData = fis.read(); System.out.println(readData); fis.close(); } catch (FileNotFoundException e) { System.out.println("文件路径包含特殊字符,处理不当"); e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值