Дизайн программы при использовании BufferedWriter, многократно открывать и закрывать файл? - PullRequest
1 голос
/ 17 апреля 2019

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

Во-первых, является ли BufferedWriter с FileWriter разумным способом сделать это?

Во-вторых, по-видимому, я не хочу открывать и закрывать это каждый раз, когда я хочу что-то написать (несколько раз в секунду).

Но если я использую try с ресурсами, то мне пришлось бы поместить в эту попытку практически всю программу, это нормально?

На данный момент скелет выглядит так:

try (FileWriter writer = new FileWriter("filename.txt");
     BufferedWriter bw = new BufferedWriter(writer)) {

} catch (IOException e) {
    //catch IO error
}

for (//main loop){
    bw.write(string);
    for (//several sub loops){
        bw.write(//more strings);
    }
    for (//several sub loops){
        bw.write(//more strings);
    }
}

bw.write(//final string);

try {
    bw.close();
} catch (IOException ex) {
    //catch IO error
}

Это выглядит разумно или есть лучший способ? Заранее большое спасибо за помощь.

Редактировать - спасибо всем за помощь, полностью ответил на мои вопросы.

Ответы [ 4 ]

2 голосов
/ 17 апреля 2019

Во-первых, является ли BufferedWriter с FileWriter разумным способом сделать это?

Да, это должен быть наиболее удобный способ сделать это.

Во-вторых, по-видимому, я не хочу открывать и закрывать это каждый раз, когда я хочу что-то написать (несколько раз в секунду).

Вы действительно не должны.Но вы бы так или иначе перезаписывали свой прогресс каждый раз, когда открываете файл.Это потому, что вы не сказали FileWriter добавить в существующий файл (через new FileWriter("filename.txt", true);.

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

Я не вижу в этом проблемы. Вы можете (и должны) всегда перемещать свою логику в собственные методы или классы, которые могут возвращать Strings для написания. Таким образом, вы отделяете действительную бизнес-логику от технической логики записи файлов и структурируете свой код, делая его более понятным.

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

1 голос
/ 17 апреля 2019

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

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

package my.tests;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.function.Consumer;

public class WriterTest {
    public static final String TARGET_NAME = "filename.txt";

    public void performMainLoop() {
        performWrites( this::mainLoop, TARGET_NAME );
    }

    public void performWrites( Consumer<Writer> writeActor, String targetName ) {
        FileWriter fileWriter;
        try {
            fileWriter = new FileWriter(targetName);
        } catch ( IOException e ) {
            System.out.println("Open failure: " + e.getMessage());
            e.printStackTrace();
            return;
        }

        BufferedWriter bufferedWriter = null;
        try {
            bufferedWriter = new BufferedWriter(fileWriter);
            writeActor.accept(bufferedWriter);

        } finally {
            if ( bufferedWriter != null ) {
                try {
                    bufferedWriter.close();
                } catch ( IOException e ) {
                    System.out.println("Unexpected close failure: " + e.getMessage());
                    e.printStackTrace();
                }
            } else {
                try {
                    fileWriter.close();
                } catch ( IOException e ) {
                    System.out.println("Unexpected close failure: " + e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

    public void mainLoop(Writer writer) {
        for ( int loopNo = 0; loopNo < 10; loopNo++ ) {
            try {
                writer.write("Loop [ " + Integer.toString(loopNo) + " ]\n");

            } catch ( IOException e ) {
                System.out.println("Unexpected write failure: " + e.getMessage());
                e.printStackTrace();
                return;
            }
        }
    }
}
1 голос
/ 17 апреля 2019

Вполне нормально поместить весь код в процедуру try-catch.Всякий раз, когда у вас возникают проблемы с записью в файл, он просто перехватывает его и не выдает ошибку.Тем не менее, я бы порекомендовал вам попробовать эту структуру только с одной процедурой try-catch.

try  { (FileWriter writer = new FileWriter("filename.txt");
 BufferedWriter bw = new BufferedWriter(writer)) 

for (/*main loop*/){
   bw.write(string);
   for (/*several sub loops*/){
    bw.write(/*more strings*/);
    }
for (/*several sub loops*/){
    bw.write(/*more strings*/);
    }
   }

bw.write(/*final string*/);


bw.close(); 


} catch (IOException e) {
   System.out.println("error");
}

PS: Если вы комментируете что-то между каким-то кодом, используйте это: / * comment * / вместо этого: //потому что он закомментирует всю строку.

1 голос
/ 17 апреля 2019

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

Вот как работает try-catch-with-resources - он закрывает ресурсы при выходе из блока try. Если это вас беспокоит, не используйте эту конструкцию, и вы сами управляете writer.

Выше скелет не будет работать, так как первый try откроет и закроет ваших авторов;

...