【问题标题】:Filereader null declarations and appending best practiceFilereader null 声明和附加最佳实践
【发布时间】:2012-02-25 02:46:17
【问题描述】:

我想优化我的文件阅读器功能,但不确定在 try 循环之外声明 null 是否是最佳做法。此外,循环并将字符附加到 Stringbuffer 是否被认为是不好的做法?我想在这里使用异常处理,但也许使用另一种结构更好?欢迎任何建议,谢谢。

public String readFile(){
File f = null;
FileReader fr = null;
StringBuffer content = null;
try{
f = new File("c:/test.txt");
fr = new FileReader(f);
int c;          
while((c = fr.read()) != -1){               
if(content == null){
content = new StringBuffer();
}

content.append((char)c);
        }

fr.close();         
    }
catch (Exception e) {
throw new RuntimeException("An error occured reading your file");
    }       
    return content.toString();
}

}

【问题讨论】:

    标签: java loops exception-handling filereader stringbuffer


    【解决方案1】:

    建议:

    1. 正确缩进代码。您问题中的内容看起来像是狗的早餐。

    2. 您不需要在 try / catch 块中初始化 f。构造函数不能以您使用它的方式抛出Exception

    3. 事实上,你根本不需要声明它。只需内联new File(...)

    4. 事实上,您甚至不需要这样做。使用FileReader(String) 构造函数。

    5. 在循环内初始化StringBuffer 没有意义。潜在的性能优势很小,仅适用于文件为空或不存在的边缘情况。在所有其他情况下,这是一种反优化。

    6. 不要抓住Exception。捕获您期望抛出的异常并允许所有其他异常传播。意外异常可能是由于您的程序中的错误造成的,需要与其他异常处理。

    7. 当你发现异常时,不要丢弃证据。对于意外异常,要么打印/记录异常、其消息及其堆栈跟踪,要么将其作为引发异常的“原因”传递。

    8. FileReader 应该在 finally 子句中关闭。在您的代码版本中,如果在创建对象之后和调用 close() 之前出现异常,则不会关闭 FileReader。这将导致文件描述符泄露,并且可能在您的应用程序中导致问题。

    9. 更好的是,使用新的 Java 7“尝试使用资源”语法,它会自动关闭“资源”(见下文)。

    10. 您一次从文件中读取一个字符。这是非常低效的。您需要将Reader 包装在BufferedReader 中,或者使用(例如)read(char[], int, int) 一次读取大量字符

    11. 使用StringBuilder 而不是StringBuffer ...除非您需要线程安全的字符串汇编器。

    12. RuntimeException 中包装异常是不好的做法。它使调用者难以处理特定的异常......如果需要......甚至使打印一个体面的诊断更加困难。 (并且假设您没有像您的代码那样丢弃原始异常。)

    注意:如果你按照第8点而不是第9点的建议,你会发现如果你在try块中打开文件,你会发现frnull的初始化是必要的。


    我是这样写的:

    public String readFile() throws IOException {
      // Using the Java 7 "try with resource syntax".
      try (FileReader fr = new FileReader("c:/test.txt")) {
        BufferedReader br = new BufferedReader(fr);
        StringBuilder content = new StringBuilder();
        int c;          
        while ((c = br.read()) != -1) {               
          content.append((char)c);
        }
        return content.toString();
      }
    }
    

    进一步的优化是使用File.length() 找出文件大小(以字节为单位)并将其用作StringBuilder 的初始大小。但是,如果文件通常很小,这可能会使应用程序变慢。

    【讨论】:

    • try (FileReader fr = new FileReader("c:/test.txt")) 这在 Java 中合法吗?尝试不使用 Catch 吗?用参数试试?另外,如果你有一个 try/catch 块,你为什么要抛出 IOException ?最后,当您返回内容时,内容超出范围。
    • 在 Java 7 语法中是合法的。这在 Java 6 或更早版本中不起作用。见这里:docs.oracle.com/javase/tutorial/essential/exceptions/…
    • @RyanAmos - 1) 是的,它是合法的 Java 7 语法。 2) 是的,尝试不使用 catch 是合法的……见 1)。 3) 是的,见 1)。 4) 因为我没有捕捉到 IOException。 5) 哎呀...我会解决的。
    • @StephenC 这很酷。我没见过……你每天都学到新东西,嗯? +1
    【解决方案2】:
    public String readFile() {
        File f = new File("/Users/Guest/Documents/workspace/Project/src/test.txt");
        FileReader fr = null;
        BufferedReader br = null;
        StringBuilder content = new StringBuilder();;
        try {
            fr = new FileReader(f);
            br = new BufferedReader(fr);
            //int c;
            //while ((c = fr.read()) != -1) {
                //content.append((char) c);
            //}
            String line = null;
            while((line = br.readLine()) != null) {
                content.append(line);
            }
            fr.close();
            br.close();
        } catch (Exception e) {
            // do something
    
        }
        return content.toString();
    }
    

    使用缓冲阅读器,您将获得 70% 以上的改进,除非您需要同步,否则请使用字符串生成器而不是字符串缓冲区。

    在一个 10MB 的文件上运行 50 次并取平均值

    • 不需要在try里面放任何不需要异常处理的东西
    • 不需要那个 if 子句,因为它只会出现一次,所以你在浪费时间 - 检查每个字符
    • 没有要抛出的运行时异常。

    结果: 最快到最慢的组合:

    1. 字符串生成器和缓冲读取器逐行:211 ms
    2. 字符串缓冲区和缓冲读取器逐行:213 ms
    3. 字符串生成器和按字符缓冲读取器:348 毫秒
    4. 字符串缓冲区和按字符缓冲的读取器:372 ms
    5. 字符串生成器和文件读取器 char by char: 878
    6. 字符串缓冲区和文件读取器 char by char:935 毫秒
    7. 字符串:非常慢

    所以使用字符串生成器+缓冲阅读器并使其逐行读取以获得最佳效果。

    【讨论】:

    • @StephenC,同意!因为测试错误的文件路径而把它留在那里:)
    猜你喜欢
    • 1970-01-01
    • 2010-10-07
    • 2018-07-19
    • 2013-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多