Zapis do jednego pliku

0

Jakiś czas temu pisałem programik to eksportu plików z cvs do excela wraz z agregacją danych. Klient teraz zarzyczył sobie dodatkową funkcję dos banalną ale coś nie mogę tergo ogarnąć. Mało tego zarzyczył sobie dziś popołudniu na jutro rano. Potrzebuje aby agregowane rekordy nie zapisywały się w oddzielnych plikach a w jednym. Czyli jeden plik IN równa się jeden plik OUT. W tej chwili miałem jedne zagregowany rekord równał sie jeden plik. Wrzucam cześć kodu gdzie prawdopodobnie powinienem nanieść poprawkę.

        logger.info("Preparation of order");
        List<String> headers = getHeaders(inputPath);
        LinkedHashMap<String, List<List<Object>>> res = new LinkedHashMap<>();
        HashSet<String> orders = new HashSet<>();

        entries.forEach(entry -> {
            int cutoff = 0;
            if (orders.contains(entry.get(0) + entry.get(1))) {
                cutoff = 7;
            }
            orders.add(entry.get(0) + entry.get(1));
            List<String> csvTokens = Streams.stream(entry.iterator()).collect(Collectors.toList());
            List<String> secondPart = csvTokens.subList(cutoff, csvTokens.size());
            Stream<Object> nulls = Collections.nCopies(cutoff, null).stream();
            List<Object> result = Stream.concat(nulls, secondPart.stream()).collect(Collectors.toList());
            List<List<Object>> x = res.getOrDefault(entry.get(0), new ArrayList<>());
            x.add(result);
            res.put(entry.get(0), x);
        });

        res.entrySet().forEach(it -> {
            Path csvPath = null;
            try {
                csvPath = File.createTempFile("prefix-", "-suffix").toPath();

            } catch (IOException e) {
                e.printStackTrace();
            }
            if(!String.format(it.getKey()).equals(headers.get(0))) {
                Path filename = Paths.get(directoryPath.toString(), String.format("%s.xlsx", it.getKey()));
                try (FileWriter out = new FileWriter(csvPath.toString());
                     CSVPrinter printer = new CSVPrinter(out, CSVFormat.EXCEL.withHeader(headers.toArray(new String[0])).withQuote('"').withDelimiter(DELIMITER))) {
                    it.getValue().forEach(ss -> {
                        try {
                            printer.printRecord(ss);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    });
                } catch (IOException e) {
                    e.printStackTrace();
                }
                try {
                    csvToXlsx(csvPath, filename);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });



    }


1

Fatalny jest ten kod - magic numbery, zmienne nazwane „x” czy typu Object. Poza tym nie zrozumiałem co chcesz zrobić. Może odpal debugger, będzie szybciej. Testów zakładam, że nie ma.

1

Potwierdzam. Masz pętle res.entrySet().forEach(it -> { a w niej warunek który wykrywa nowy dataset i robi Path filename = Paths.get(directoryPath.toString(), String.format("%s.xlsx", it.getKey()));
Musisz przenieść to tworzenie nowego pliku przed pętle.

Swoją drogą kod to dramat.

0

Jest to prosty programik który prawdopodobnie zostanie użyty tylko raz i to przeze mnie. Oprócz zmiennych z ciekawości co byście zmienili jeszcze
w nim ?

0

Ja bym zaczął od jakiegoś ludzkiego error handlingu, po co co linijke masz te try..catch skoro i tak wszędzie tylko printujest stack trace? :D

1

@SpectreDev:

Potrzebuje aby agregowane rekordy nie zapisywały się w oddzielnych plikach a w jednym.

Z tego co pamiętam, to w pliku miałeś dwie kolumny, które były kluczem po którym wiedziałeś czy rekord leci do tego pliku czy zaczynasz nowy i tam zapisujesz.

Jest to prosty programik który prawdopodobnie zostanie użyty tylko raz i to przeze mnie. Oprócz zmiennych z ciekawości co byście zmienili jeszcze
w nim ?

Chodzi o styl. Jak się raz nauczysz pisać źle, to potem będziesz tylko to powielał.
Moim zdaniem w tym kodzie dzieje się za dużo. Konkretne problemy powinieneś rozbić. To chyba przykład aplikacji typu parser. U ciebie jest wszystko w jednym i rozwój takiej aplikacji to przewalanie jej w 80% aby robiła nowe rzeczy.

Jak dla mnie powinieneś sobie zrobić klaskę ala parser, która parsuje dane. Potem w klasce zapisującej wskazujesz ten obiekt jako argument i np. interfejs convertera. W zależności od sposobu modyfikacji wstrzykujesz inną implementację konwertera.

0

@.andy: zgadzam się z Tobą. Tej klasy nikt nie rusza oprócz mnie i to ma być użuyte raz i zapomniane dlatego też nie zabradzo przywiązywałem do stylu. Mój ostatni większy projekt który robiłem to z code review wracało jak było o jedną dużo spacje za dużo albo o jedną przerwę miedzy wierszami za dużo. To co wyżej to by w życiu nie przeszło :)

0

Wyciągnąłem sobie to tak ale nadal coś jest nie tak bo teraz nic nie mam w pliku

 Path filename = Paths.get(directoryPath.toString(), String.format("%s.xlsx", "Test"));
        Path csvPath = File.createTempFile("prefix-", "-suffix").toPath();
        FileWriter out = new FileWriter(csvPath.toString());
        CSVPrinter printer = new CSVPrinter(out, CSVFormat.EXCEL.withHeader(headers.toArray(new String[0])).withQuote('"').withDelimiter(DELIMITER));

        res.entrySet().forEach(it -> {
            it.getValue().forEach(ss -> {
                System.out.println(ss);
                try {
                    printer.printRecord(ss);
                } catch (IOException e) {
                    e.printStackTrace();
                }

            });
        });

        try {
            csvToXlsx(csvPath, filename);
        } catch (Exception e) {
            e.printStackTrace();
        }
1
  1. Ja nie widzę zamykania pliku

  2. nadal masz te brzydkie try catch. Jesteś zainteresowany częściowo zgodnym plikiem? Chyba nie ...

1

Jesteś zainteresowany częściowo zgodnym plikiem ? Możesz mi wytłumaczyć ? — SpectreDev 2021-07-02 09:43

Taki algorytm jak widać, może mieć awarię (wyjątek) na jednej linii, ukryć to, i kontynuować. W zastosowaniach jakie ja uprawiam, taki plik, z ukrytym brakiem jest bezwartościowy.

Co więcej, z braku informacji o takim fakcie, groźny.

@SpectreDev
dodam z imienną dedykacją, nt "klasy tylko dla siebie".
Nie da się myśleć "najpierw poprawmy błąd, a potem kiedyś poprawię estetykę / jakość kodu" - ten tok myślenia prowadzi donikąd.
Kod który jest brzydki, nieładny, nieczytelny, jest niemal pewne, ze zawiera błędy, i to niejeden.
Źle zbudowanego domu nie da się ulepszyć malując dach.

1 użytkowników online, w tym zalogowanych: 0, gości: 1