Создание файла CSV каждые 2 часа с использованием Java - PullRequest
0 голосов
/ 24 сентября 2018

У меня есть требование в нашем проекте генерировать файл CSV каждые 2 часа, используя программу Java.Я хочу создать папку с датами в ежечасном файле CSV. Это означает, что каждый файл CSV содержит данные за 2 часа (конфигурируемые).Я могу создать почасовой файл CSV.Но я не могу создать настраиваемую почасовую базу CSV. Я не использую ScheduledExecutorService.Я хочу простой способ решить эту проблему.

public static boolean writeFileHourlyBasis(String tenantName, String clusterName, String contentSourceName,
        String fileContent) {

    String reconciliationLogPath = AppConfigHashMap.getPropertyValue("ReconciliationLogFolder");

    if (reconciliationLogPath != null) {
        File fullReconciliationLogPath = new File(reconciliationLogPath + File.separator + tenantName
                + File.separator + clusterName + File.separator + contentSourceName + File.separator + formatter.format(new Date()));
        if (fullReconciliationLogPath.mkdirs() == true){

            logger.debug("Folder " + fullReconciliationLogPath + " created.");
        }
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("HH");
            String fileName = tenantName + "_" + dateFormat.format(new Date()) + ".csv";
            File file1 = new File(fullReconciliationLogPath, fileName);
            String headerString = "";           

            if (!file1.exists()) {
                headerString = "DateTimeUTC,DateTime,Transcript->TranscriptId,Target->ReturnCode,Target->Status,Target->Message,MessageId,StatusMessage \n";
            }else{
                if(isNewLine){
                    headerString="\n";
                }
                isNewLine=false;
            }
            FileWriter datawriter = new FileWriter(file1, true);
            datawriter.append(headerString);
            datawriter.append(fileContent);
            datawriter.append("\n");
            datawriter.flush();
            datawriter.close();
        } catch (Exception e) {
            logger.warn("Exception occurred while writing Reconcilation log :" + e.getMessage());
            return false;
        }
    }else{
        //TODO: log.error("Reconciliation log enabled, but path not provided!");
        logger.warn("Reconciliation log enabled, but path not provided!");
        return false;
    }
    return true;

}

Может ли кто-нибудь помочь мне решить эту проблему.

1 Ответ

0 голосов
/ 24 сентября 2018

Я не использую ScheduledExecutorService.Я хочу простой способ решения этой проблемы.

У вас уже есть ответ: Платформа Executors была добавлена ​​в Java, чтобы быть простым способом для решения этой проблемы.Исполнители абстрагируются от сложных и запутанных деталей обработки фоновых задач и потоков.

Вы должны использовать ScheduledExecutorService для своих целей.

Исполнители могут показаться пугающими на первый взгляд, но их использование на практике довольно просто.Прочтите руководство по Oracle.Затем посмотрите примеры кода в Stack Overflow, других блогах и т. Д.

Совет. Поиск переполнения стека осуществляется с помощью внешней поисковой системы, такой как DuckDuckGo / Bing / Google, с критерием site:StackOverflow.com.Встроенная функция поиска в переполнении стека анемична и смещена в сторону вопросов, а не ответов.

Определите службу исполнителя, поддерживаемую пулом потоков.

ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

Определите вашу задачу для запуска как Runnable.

Runnable task = new Runnable() {
    @Override
    public void run () {
        … stuff to do goes here
    }
}

Передать объект Runnable в службу исполнителя.Расскажи как часто бегать.Вы также проходите начальную задержку;здесь мы проходим ноль, чтобы начать немедленно.

scheduledExecutorService.scheduleAtFixedRate( task , 0 , 2 , TimeUnit.HOURS ); 

Совет. Об использовании ScheduledExecutorService (SES): две важные вещи:

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

Поэтому измените Runnable, показанный выше.

Runnable task = new Runnable() {
    @Override
    public void run () {
        try {
            … stuff to do goes here
        } catch ( Exception e ) {
            … Handle any unexpected exceptions bubbling up to avoid silently killing your executor service. 
        }
    }
}

Совет: Никогда не используйте ужасные старые классы даты и времени, такие как Date, CalendarSimpleDateFormat.Они были вытеснены несколько лет назад современными java.time классами.


Совет. При записи момента в имени файла следуйте стандарту ISO 8601 для представления значений времени и даты в виде текста.

Эти форматы по умолчанию используются в классах java.time при разборе или генерации строк.

Для имен файлов вы можете использовать альтернативные «базовые» форматы, определенные в стандарте. Basic означает, что использование разделителей сведено к минимуму.

Обязательно избегайте обратной косой черты, прямой косой черты и символов двоеточия.Это запрещено в файловых системах DOS / Windows, Unix и macOS / iOS, соответственно.


Совет. Не пишите собственный CSV-код.Используйте библиотеку Apache Commons CSV для чтения и записи файлов CSV или табуляции.Это хорошо работает по моему опыту.


Пример приложения

Вот целый пример, содержащийся в одном файле .java.

У нас есть несколько объектов нашего маленького класса Event.При каждом запланированном запуске мы обновляем метку времени для каждого объекта Event.Затем мы записываем все переменные-члены всех этих Event объектов в текстовый файл в формате CSV, используя библиотеку Apache Commons CSV.Каждый прогон определяется объектом Runnable.

Прогоны планируются с помощью ScheduledExecutorService, поддерживаемого пулом потоков с одним потоком.

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

package com.basilbourque.example;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExportToCsv {
    public static void main ( String[] args ) {
        ExportToCsv app = new ExportToCsv();
        app.doIt();
    }

    private void doIt () {
        System.out.println( "TRACE - doIt running at " + ZonedDateTime.now() );
        List< Event > events = List.of(
        new Event( UUID.randomUUID() , "alpha" , Instant.now() ) ,
        new Event( UUID.randomUUID() , "beta" , Instant.now() ) ,
        new Event( UUID.randomUUID() , "gamma" , Instant.now() )
        );

        Runnable task = new Runnable() {
            @Override
            public void run () {
                // Nest all this stuff of your `run` method into a `try-catch( Exception e )` to avoid having your executor cease silently.
                Instant start = Instant.now();
                System.out.print( "TRACE - Runnable starting at " + start + ". " );
                // Update the moment recorded in each `Event` object.
                events.forEach( ( event ) -> event.update() );
                // Export to CSV. Using “Apache Commons CSV” library. https://commons.apache.org/proper/commons-csv/
                // Get current moment in UTC. Lop off the seconds and fractional second. Generate text without delimiters.
                String dateTimeLabel = OffsetDateTime.now( ZoneOffset.UTC ).truncatedTo( ChronoUnit.MINUTES ).format( DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmX" , Locale.US ) );
                String fileNamePath = "myCsv_" + dateTimeLabel + ".csv";
                try (  // Try-with-resources syntax automatically closes any passed objects implementing `AutoCloseable`, even if an exception is thrown.
                BufferedWriter writer = new BufferedWriter( new FileWriter( fileNamePath ) ) ;
                CSVPrinter csvPrinter = new CSVPrinter( writer , CSVFormat.DEFAULT.withHeader( "Id" , "Name" , "When" ) ) ;
                ) {
                    for ( Event event : events ) {
                        csvPrinter.printRecord( event.id , event.name , event.when );
                    }
                    csvPrinter.flush();
                } catch ( IOException e ) {
                    // TODO: Handle i/o exception when creating or writing to file in storage.
                    e.printStackTrace();
                }
                Instant stop = Instant.now() ;
                System.out.println( "Runnable ending its run at " + start + ". Duration: " + Duration.between( start , stop ) + ".");
            }
        };

        // Schedule this task. Currently set to run every two minutes, ending after 20 minutes. Adjust as desired.
        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();  // Using a single thread here, as we have only a single series of tasks to be executed, no multi-tasking. 
        try {
            scheduledExecutorService.scheduleAtFixedRate( task , 0 , 2 , TimeUnit.MINUTES );  // Schedule our task to run every so often.
            try {
                Thread.sleep( TimeUnit.MINUTES.toMillis( 20 ) );  // Sleep this main thread for a while to let our task running on the background thread do its thing a few times.
            } catch ( InterruptedException e ) {
                System.out.println( "TRACE - Our main thread was woken earlier than expected, and interrupted our run. " );
                e.printStackTrace();
            }
        } finally {
            System.out.println( "Shutting down the scheduledExecutorService at " + ZonedDateTime.now() );  // Generally best to log in UTC, `Instant.now()`.
            scheduledExecutorService.shutdown();  // Always shutdown your executor, as it may otherwise survive your app exiting, becoming a zombie, continuing to run endlessly.
        }
        System.out.println( "App running on main thread ending at " + Instant.now() + "." );
    }

    class Event {
        public UUID id;
        public String name;
        public Instant when;

        public Event ( UUID id , String name , Instant when ) {
            this.id = id;
            this.name = name;
            this.when = when;
        }

        public void update () {
            this.when = Instant.now();
        }
    }
}

При запуске.

TRACE - не работает в 2018-09-24T20: 16: 25.794081-07: 00[America / Los_Angeles]

TRACE - Работает с 2018-09-25T03: 16: 25.832025Z.Runnable заканчивает свой пробег в 2018-09-25T03: 16: 25.832025Z.Продолжительность: PT0.025342S.

TRACE - Запуск с 2018-09-25T03: 18: 25.829634Z.Runnable заканчивает свой пробег в 2018-09-25T03: 18: 25.829634Z.Продолжительность: PT0.001121S.

Файлы, показанные на этом снимке экрана.

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...