Нулевые объявления Filereader и добавление лучших практик - PullRequest
0 голосов
/ 25 февраля 2012

Я хочу оптимизировать функцию чтения файлов, но не уверен, что лучше всего объявлять нули вне цикла try. Кроме того, считается ли зацикливание и добавление символов в 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();
}

}

Ответы [ 2 ]

3 голосов
/ 25 февраля 2012

Совет:

  1. Правильный отступ вашего кода. Материал в вашем вопросе выглядит как собачий завтрак.

  2. Вам не нужно инициализировать f внутри блока try / catch. Конструктор не может выбросить Exception так, как вы его используете.

  3. На самом деле, вам вообще не нужно это объявлять. Просто вставьте new File(...).

  4. На самом деле, вам даже не нужно этого делать. Используйте конструктор FileReader(String).

  5. Нет смысла инициализировать StringBuffer внутри цикла. Потенциальный выигрыш в производительности невелик и применяется только в крайнем случае, когда файл пуст или не существует. Во всех остальных случаях это антиоптимизация.

  6. Не поймать Exception. Поймайте исключения, которые вы ожидаете выбросить, и разрешите распространяться всем остальным исключениям. Неожиданные исключения будут вызваны ошибками в вашей программе и должны обрабатываться иначе, чем другие.

  7. Когда вы поймаете исключение, не выбрасывайте улики. В случае непредвиденного исключения либо напечатайте / запишите исключение, его сообщение и трассировку стека, либо передайте его как «причину» исключения, которое вы выбросили.

  8. FileReader следует закрыть в предложении finally. В вашей версии кода FileReader не будет закрыт, если есть исключение после создания объекта и до вызова close(). Это приведет к утечке файлового дескриптора, и может вызвать проблемы позже в вашем приложении.

  9. Еще лучше, используйте новый синтаксис Java "try with resource", который обеспечивает автоматическое закрытие "ресурса" (см. Ниже).

  10. Вы читаете из файла по одному символу за раз. Это очень неэффективно. Вам нужно либо обернуть Reader в BufferedReader, либо прочитать одновременно большое количество символов, используя (например) read(char[], int, int)

  11. Используйте StringBuilder вместо StringBuffer ... если только вам не нужен поточно-ориентированный сборщик строк.

  12. Упаковывать исключения в RuntimeException - это плохая практика. Для вызывающего абонента трудно обрабатывать определенные исключения ... если это необходимо ... и даже затрудняется печать приличной диагностики. (И это предполагает, что вы не выбросили исходное исключение, как это делает ваш код.)

Примечание: если вы будете следовать советам пункта 8, а не 9, вы обнаружите, что инициализация от fr до null необходима, если вы откроете файл в блоке try.


Вот как бы я написал это:

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. Однако, если файлы обычно небольшие, это может замедлить работу приложения.

0 голосов
/ 25 февраля 2012
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% + улучшение, используйте строитель строк вместо строкового буфера, если вам не нужна синхронизация.

запустил файл размером 10 МБ 50 раз и усреднил

  • нет необходимости помещать что-либо, что не требует обработки исключений, внутри try
  • нет необходимости в этом условии if, потому что оно будет истинным только один раз, и поэтому вы тратите время - проверяя его для каждого символа
  • Нет исключений времени выполнения для выброса.

Результаты: самая быстрая комбинация к самой медленной:

  1. построитель строк и буферизованный считыватель строка за строкой: 211 мс
  2. строковый буфер и буферизованный считыватель построчно: 213 мс
  3. строитель строк и буферизованный читатель char на char: 348 мс
  4. строковый буфер и буферизованный читатель char на char: 372 мс
  5. сборщик строк и считыватель файлов char by char: 878
  6. строковый буфер и считыватель файлов char by char: 935 мс
  7. строка: очень медленно

, поэтому используйте построитель строк + буферизованный ридер и заставляйте его читать построчно для достижения наилучших результатов.

...