我的项目中要求使用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;
}
任何人都可以帮助我解决这个问题。
答案 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)的两件重要的事情:
因此,修改上面看到的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
,Calendar
,SimpleDateFormat
。多年前,现代的 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。
此屏幕截图中显示的文件。