1

Когда я хочу написать Java-код для ввода текста в файл, обычно это выглядит примерно так:«Стойкие потоки» для Java FileWriter?

File logFile = new File("/home/someUser/app.log"); 
FileWriter writer; 

try { 
    writer = new FileWriter(logFile, true); 

    writer.write("Some text."); 

    writer.close(); 
} catch (IOException e) { 
    e.printStackTrace(); 
} 

Но что, если я делаю тонна операций записи спина к спине? Что делать, если я регистрирую десятки, сотни и даже тысячи операций записи в секунду?

Точно так же, как базы данных (annd JDBC) позволяют «постоянные соединения» (соединения, которые остаются открытыми для нескольких вызовов), есть способ иметь «постоянные потоки», которые не нужно открывать/закрывать через несколько write(String) invocations? Если да, то как это будет работать? О каких подводных камнях/оговорках я должен знать? Заранее спасибо!

+1

BTW в вашем примере, если 'write' генерирует исключение, автор не закрывается сразу после' write'. – Beryllium

ответ

1

Если вы посмотрите на эту реализацию

class Logger { 
    private final BufferedWriter w; 

    public Logger(final File file) throws IOException { 
     this.w = new BufferedWriter(new FileWriter(file)); 
     LoggerRegistry.register(this); 
    } 

    public void log(String s) throws IOException { 
     synchronized (this.w) { 
      this.w.write(s); 
      this.w.write("\n"); 
     } 
    } 

    public void close() throws IOException { 
     this.w.close(); 
    } 
} 

этот файл остается открытым.

Если у вас несколько потоков, вам необходимо синхронизировать метод записи (но это необходимо учитывать в любом случае).

Есть, возможно, эти проблемы, если файл остается открытым:

  • В теории, можно запустить из файловых дескрипторов. Они могут быть ограничены (см., Например, ulimit -a о системах Linux): каждый регистратор потребляет один дескриптор.

  • Если вы используете FileWriter без буферизации, у вас есть вызовы ввода/вывода для каждого вызова write. Это может быть довольно медленным.

  • Если вы используете BufferedWriter на вершине FileWriter, вы должны убедиться, что он получает закрыта в конце вашей программы, в противном случае оставшееся содержимое в буфере не могут быть записаны на диск. Таким образом, вам понадобится блок try/finally вокруг вашей программы, который должен закрыть все регистраторы правильно.

Поэтому вам необходимо зарегистрировать всех регистраторов. Это упрощенная версия (не потокобезопасный):

class LoggerRegistry { 
    private final static List<Logger> loggers = new ArrayList<Logger>(); 

    public static void register(Logger l) { 
     loggers.add(l); 
    } 

    public static void close() { 
     for (Logger l : loggers) { 
      try { 
       l.close(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 

и использовать это в вашей основной программе, как это:

public static void main(String[] args) throws IOException { 
    try { 
     final Logger l = new Logger(new File("/tmp/1")); 
     l.log("Hello"); 

     // ... 

    } finally { 
     LoggerRegistry.close(); 
    } 
} 

Если у вас есть веб-приложение, вы могли бы назвать close метод в ServletContextListener (метод contextDestroyed).

Наибольшее усиление производительности, вероятно, является BufferedWriter. Это преимущество теряется, если вы открываете/закрываете его для каждой операции записи, так как close должен позвонить flush. Таким образом, комбинация открытого файла вместе с буферизацией будет довольно быстрой.

0

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

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

+0

Спасибо @sanbhat (+1) - когда вы говорите: «Один из недостатков этого подхода заключается в том, что файл будет храниться в FileWriter, даже если нет действий записи. *», Что это подразумевает? Означает ли это, что файл «заблокирован»? Может ли несколько потоков ведения журнала не записываться в файл? Каковы ограничения, наложенные этой стратегией? ** Что самое важное **, это приведет к увеличению производительности? Если нет, то в чем смысл этого?!? Еще раз спасибо! –

+1

@TicketMonster, пожалуйста, проверьте правильность изменения – sanbhat

+0

Ahh, очень приятно - еще раз спасибо @sanbhat. Извините, что здесь придирчиво, но 2 вещи: (1) «никаким другим ** процессом ** не может записываться в файл журнала», вы имеете в виду: другие потоки, другие JVM или другие процессы на системном уровне (или все 3)? Например, может ли, скажем, сценарий Perl записывать в тот же файл журнала, пока он «заблокирован» Java 'FileWriter'? И (2) можете ли вы указать мне на любую документацию Oracle/Java, которая поддерживает ваши заявления о блокировке файлов? Не то, чтобы я не верю вам (я знаю!), Но мне нужно пойти к моему боссу с доказательством концепции и вам нужно будет ссылаться на refs. Еще раз спасибо! –

 Смежные вопросы

  • Нет связанных вопросов^_^