2015-09-08 6 views
4

Я столкнулся с проблемой с BufferedWriter, когда я записываю данные в один файл с некоторыми потоками.Как установить размер буфера на BufferedWriter над FileWriter

Я установил размер буфера BufferedWriter, но независимо от того, какой номер я устанавливаю, он сбрасывает данные на диск, когда буфер равен 8192 (размер буфера по умолчанию), а не размер, который я задал (здесь 16384). Есть ли проблема с моим кодом?

Это, как я построения BufferedWriter:

new BufferedWriter(new FileWriter(fileName, true), 16384); 

Это полный код:

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 

public class Test1 { 
    public static void main(String[] args) throws IOException { 
     for(int i =0;i<10;i++){ 
      MyThread r = new MyThread(); 
      Thread t = new Thread(r); 
      t.start(); 
     } 
    } 
} 

class MyThread implements Runnable { 
    public void run() { 
     String s = "{addffffffkkkljlkj2015dd}\n"; 
     BufferedWriter bw = null; 
     try { 
      bw = new BufferedWriter(new FileWriter(
        "/Users/liaoliuqing/Downloads/1.txt", true),16384); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     for(int i =0 ; i<1000; i++){ 
      try { 
       bw.write(String.format("%03d", i)+s); 
       //bw.flush(); 
      } catch (IOException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
} 
+0

Я запустить программу в debian и mac, он получает тот же результат. Независимо от того, как я изменяю размер буфера, он не влияет. –

+1

И какой эффект вы хотите? –

+0

, если размер буфера установлен на 16384, он должен записывать на диск, когда данные составляют 16384 байта, а не 8192. Теперь независимо от того, что я установил, он записывает на диск каждые 8192 байта. –

ответ

1

Я решить эту проблему с помощью OutputStream, не писатель, вот код:

bw = new BufferedOutputStream(
       new FileOutputStream(new File("/Users/liaoliuqing/Downloads/1.txt"),true),165537); 
+0

Хорошо для вас, но это странно, поскольку делегаты 'Writer' над' OutputStream' и все поведение (флаг добавления, размер буфера, точные операции при записи ASCII) идентичны. Любые другие изменения? – Javier

0

То, что вы видите, это не размер буфера BufferedWriter, но размер буфера, используемого внутри FileWriter. Цитирование из документации Java (http://docs.oracle.com/javase/7/docs/api/java/io/FileWriter.html)

Конструкторы этого класса предполагают, что кодировка символов по умолчанию и размер по умолчанию байт буфера являются приемлемыми. Чтобы сами определить эти значения, создайте OutputStreamWriter в FileOutputStream.

Так что, если вы хотите иметь хороший контроль зерна на том, когда данные действительно записаны на диск, который вы должны создать экземпляр BufferedWriter в

bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File('my_file.txt),true))); 
+0

Как это помогает вам контролировать ? размер буфера –

+0

Я настроен на это: м.т. = новый BufferedWriter (новый OutputStreamWriter ( \t \t \t \t \t новый FileOutputStream (новый файл ("/ Users/liaoliuqing/Загрузки/1.txt"), правда)), 65536) ; bw.write (String.format ("% 03d", i) + s); \t \t \t bw.flush(); my s tring составляет 27340 байт, поэтому размер буфера достаточно велик, чтобы содержать строку. но все равно он записывает на диск каждые 8192 байта. –

+0

Мой ответ был основан на документации: поскольку он указывает «указать эти значения» (множественное число), я предположил, что в этом случае у FileOutputStream не будет собственного буфера .... –

2

FileWriter фактически использует свой собственный фиксированного размера буфера 1024 байт , С другой стороны, BufferedWriter показывает, что он использует размер буфера 8192 байта (по умолчанию), который может быть настроен пользователем на любой другой желаемый размер.

И для дальнейшей грязной воды реализация Java 6 OutputStreamWriter фактически делегирует StreamEncoder, который использует свой собственный буфер с размером по умолчанию 8192 байта. И буфер StreamEncoder настраивается пользователем, хотя нет возможности получить к нему доступ непосредственно через прилагаемый OutputStreamWriter.

+2

Этот ответ, похоже, был скопирован от https://stackoverflow.com/questions/6976893/in-java-what-is-the-advantage-of-using-bufferedwriter-to-append-to-a-file/6976933#6976933, который содержит некоторые дополнительные полезные ссылки. –

+0

Действительно. Но копия была бы неправильным словом. Я мог бы перефразировать его, чтобы предложить мне мой ответ, но дело было в том, чтобы передать информацию и не переписывать ее, если она уже существует. Я пропустил эти ссылки, чтобы поддерживать минимальные и релевантные и открытые двери для OP, чтобы самостоятельно провести исследование.:) –

1

Есть ли проблема с моим кодом?

Несколько. В основном: потенциальные ошибки ввода-вывода и параллелизма. Размер файлового буфера может быть менее опасным (и тот, с которым вы не можете эффективно справиться).

  • Попытка уже открыть файл открыт. Все ваши потоки пытаются записать в один файл (1.txt). Это может быть проблемой. FileWriter documentation says:

    Некоторые платформы, в частности, разрешить файл, который будет открыт для записи только один FileWriter (или другого объекта записи файла), в то время. В таких ситуациях конструкторы этого класса не сработают, если файл уже открыт.

  • линия может быть разрезана и смешанные.Если у вас есть несколько потоков с соответствующими буферами в какой-то момент на один и тот же выход, вам может даже не понадобиться странные условия гонки или потоки, остановленные справа от середины или операция записи, чтобы увидеть, что ваш результат поврежден.

    В качестве решения (если ваши потоки должны иметь один и тот же вывод), вы можете использовать общий объект с синхронизированным доступом, чтобы заботиться о фактической записи. В моем примере я применил SafeAppender, но, вероятно, там есть лучшие альтернативы. не

  • Нет смыва и закрытия буферов будет означать (хвост) ваши данные будут потеряны (как слезы в дожде). Наконец, блок, как правило, хорош, чтобы позаботиться об этом.

  • Кроме того, как указано другими пользователями, BufferedWriterразмер буфера не влияет на размер буфера в FileOutputStream (и так FileWriter). И это выглядит так, что API java.io и java.nio не предлагают никакого способа с этим справиться. Если вы посмотрите на источники библиотеки Java, вы можете заметить, что размер буфера BufferedWriter просто означает количество символов, которое вы храните, прежде чем записывать на выходе делегата. Размер по умолчанию (8192) является оптимальным для большинства случаев, и увеличение его может означать больше проблем (потенциально потерять больше данных), чем преимуществ.

Это мой код, если он служит вам:

// http://stackoverflow.com/questions/32451526/how-to-set-the-buffer-size-on-a-bufferedwriter-over-a-filewriter 
public class TestWriter { 

public static class SafeAppender { 
    private BufferedWriter bw; 
    private int users = 0; 
    public SafeAppender(File f) throws IOException { 
     bw = new BufferedWriter(new FileWriter(f)); 
    } 

    public synchronized void append(String s) throws IOException { 
     bw.write(s); 
    } 
    public synchronized void incrUsers() { 
     users ++; 
    } 
    public synchronized void decrUsers() { 
     if (--users <= 0) { 
      try { 
       bw.flush(); 
       System.err.println("INFO-appender-flush()"); 
      } catch (Throwable whatever) { /* log-if-you-care*/} 
     } 
    } 
    // Might be called by GC, or not 
    @Override protected void finalize() throws Throwable { 
     try { 
      bw.close(); 
      System.err.println("INFO-appender-close()"); 
     } catch (Throwable whatever) { /* log-if-you-care */} 
     super.finalize(); 
    } 
} 

private static class MyRunnable implements Runnable { 
    final static String S = "{addffffffkkkljlkj2015dd}"; 
    SafeAppender appender; 
    String threadId; 
    public MyRunnable (SafeAppender a, String tid) { 
     appender = a; threadId = tid; 
    } 

    public void run() { 
     appender.incrUsers(); 
     try { 
      for(int i =0 ; i<1000; i++){ 
       // NOTE: Not a good idea to printStackTrace if each line fails. Let thread fail 
       String line = String.format("%s-%03d-%s\n", threadId, i, S); 
       appender.append(line); 
      } 
     } catch (IOException e) { 
      System.err.printf("ERROR-%s-%s\n", threadId, e.toString()); 
     } finally { 
      appender.decrUsers(); 
     } 
    } 
} 

public static void main(String[] args) { 
    try { 
     File f = File.createTempFile("TestWriter", ".txt"); 
     System.err.printf("INFO-main-Writing into %s\n", f.getCanonicalPath()); 
     SafeAppender appender = new SafeAppender (f); 
     for(int i =0;i<10;i++){ 
      MyRunnable r = new MyRunnable(appender, ""+i); 
      Thread t = new Thread(r); 
      t.start(); 
     } 
    } catch (Throwable e) { 
     e.printStackTrace(System.err); 
    } 
} 

} 

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

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