使用Java每2小时生成CSV文件

时间:2018-09-24 11:05:19

标签: java csv date

我的项目中要求使用Java程序每2小时生成CSV文件。 我想在基于小时的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 :(得分:3)

  

我没有使用ScheduledExecutorService。我想要解决这个问题的简单方法。

您已经有了答案:将Executors框架添加到Java就是这样简单的方法,以解决此问题。执行程序将处理后台任务和线程的棘手的细节弄糟了。

您应该使用ScheduledExecutorService来达到目的。

执行程序乍看之下似乎令人生畏,但在实践中使用它们非常简单。阅读Oracle教程。然后查看Stack Overflow和其他博客等中的代码示例。

提示:使用符合site:StackOverflow.com标准的外部搜索引擎(例如DuckDuckGo / Bing / Google)进行搜索堆栈溢出。 Stack Overflow中的内置搜索功能是贫乏的,并且偏向于问题而不是答案。

定义由线程池支持的执行程序服务。

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. 
        }
    }
}

提示:切勿使用可怕的旧日期时间类,例如DateCalendarSimpleDateFormat。多年前,现代的 java.time 类取代了它们。


提示:在文件名中写入时刻时,请遵循ISO 8601标准,以文本形式表示日期时间值。

在解析或生成字符串时, java.time 类中默认使用这些格式。

对于文件名,您可能需要使用标准中定义的替代“基本”格式。 Basic 表示最小化定界符的使用。

确保避免使用反斜杠,正斜杠和冒号字符。这些分别在DOS / Windows,Unix和macOS / iOS文件系统中被禁止。


提示:请勿编写自己的CSV代码。使用Apache Commons CSV库来读取和写入CSV或制表符分隔的文件。根据我的经验,它效果很好。


示例应用

这里是单个.java文件中包含的整个示例。

我们有小类Event的一些对象。在每次计划的运行中,我们都会更新每个Event对象的时间戳。然后,我们使用Apache Commons CSV库将所有Event对象的所有成员变量写入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-doIt运行于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