文件是计算机系统中重要的存储媒介,常用于存储数据和程序。在Java中,文件操作是非常常见的操作之一。有时候,我们需要在文件被修改后再读取其中的数据,但是文件是一直存在的,并不能通过是否生成去判断,这就需要我们在Java中实现等待文件修改后再读取数据的功能。本文将介绍如何使用Java实现该功能。
一、问题描述
这段代码的作用是将一个Excel表格中的数据提取出来,并以字符串的形式返回。具体实现过程如下:
-
根据传入的exePath和tagerPath参数构造出一个命令行字符串,该命令行字符串用于调用外部程序,将Excel表格中的数据提取到一个文本文件中。
-
调用Java的Runtime.getRuntime().exec()方法来执行上述命令行字符串,返回一个Process实例,该实例可用来控制进程并获得相关信息。
-
读取刚才生成的文本文件中的数据,并将其存储到一个字符数组中。
-
将字符数组中的数据转换成字符串,并返回该字符串。
-
在finally块中关闭文件流。
E:\ftpTest\data.txt文件文件是一直存在的,并不能通过是否生成去判断,怎么样才能等data.txt文件被exec(run)修改完后再执行读取数据?
java
public static String tableToBin(String exePath, String tagerPath) {
String dataPath = "E:\\ftpTest\\data.txt";
Reader fr = null;
int length = 0;
char ch[] = null;
// Excel.exe test_read.xlsx 文件路径
String run = exePath + " " + " " + tagerPath + " " + dataPath;
try {
//解释:Runtime.getRuntime().exec()方法返回一个Process实例,该实例可用来控制进程并获得相关信息。
Process proc = Runtime.getRuntime().exec(run);
System.out.println("读取表格并提取数据完成");
//读取数据
fr = new FileReader(dataPath);
//ch[]数组存放读取的数据
ch = new char[1024];
//length为读取的数据长度
length = fr.read(ch);
//返回读取的数据
return new String(ch, 0, length);
} catch (IOException e) {
//抛出运行时异常
throw new RuntimeException(e);
} finally {
try {
//关闭流
fr.close();
} catch (IOException e) {
//抛出运行时异常
throw new RuntimeException(e);
}
}
}
二、问题分析
如果文件是一直存在的,那么可以通过比较文件的修改时间来判断文件是否更新。可以使用Java的File类的lastModified()方法获取文件的最后修改时间,然后将其与上一次检查时的时间进行比较。如果文件的最后修改时间比上一次检查时的时间要晚,那么说明文件已经更新,可以执行发送数据的代码。你可以在一个循环中不断检查文件是否更新,如果文件更新了就执行发送数据的代码。
三、解决方案
1. 使用Java的File类的lastModified()方法
使用Java的File类的lastModified()方法获取文件的最后修改时间,然后将其与上一次检查时的时间进行比较。如果文件的最后修改时间比上一次检查时的时间要晚,那么说明文件已经更新,可以执行读取数据的代码。
示例代码:
java
public static String tableToBin(String exePath, String tagerPath) {
String dataPath = "E:\\ftpTest\\data.txt";
Reader fr = null;
int length = 0;
char ch[] = null;
long lastModified = 0;
boolean fileUpdated = false;
// Excel.exe test_read.xlsx 文件路径
String run = exePath + " " + " " + tagerPath + " " + dataPath;
try {
//解释:Runtime.getRuntime().exec()方法返回一个Process实例,该实例可用来控制进程并获得相关信息。
Process proc = Runtime.getRuntime().exec(run);
//等待文件生成
while(!fileUpdated) {
File file = new File(dataPath);
long currentModified = file.lastModified();
if(currentModified > lastModified) {
lastModified = currentModified;
Thread.sleep(1000); //等待1秒
} else {
fileUpdated = true;
}
}
//读取数据
fr = new FileReader(dataPath);
//ch[]数组存放读取的数据
ch = new char[1024];
//length为读取的数据长度
length = fr.read(ch);
//返回读取的数据
return new String(ch, 0, length);
} catch (IOException e) {
//抛出运行时异常
throw new RuntimeException(e);
} catch (InterruptedException e) {
//抛出运行时异常
throw new RuntimeException(e);
} finally {
try {
//关闭流
fr.close();
} catch (IOException e) {
//抛出运行时异常
throw new RuntimeException(e);
}
}
}
在这个示例代码中,我们将文件的最后修改时间与上一次检查时的时间进行比较,如果文件的最后修改时间比上一次检查时的时间要晚,那么说明文件已经更新,可以执行读取数据的代码。如果文件还没有更新,我们使用Java的Thread.sleep()方法等待一段时间,然后再次检查文件的最后修改时间。当文件的最后修改时间不再更新时,我们退出等待循环,执行读取数据的代码。
2. 使用Java的WatchService类
Java的WatchService类可以用于监控文件的变化,并在文件发生变化后再读取数据。使用WatchService类需要创建一个WatchService实例,并将其注册到需要监控的目录上。当目录中的文件发生变化时,WatchService会接收到通知,我们可以在通知中执行读取数据的代码。
示例代码:
java
public static String readFileAfterUpdate(String filePath) {
Reader fr = null;
int length = 0;
char ch[] = null;
try {
//创建WatchService实例
WatchService watchService = FileSystems.getDefault().newWatchService();
//将目录注册到WatchService中
Path path = Paths.get(filePath).getParent();
path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
//等待目录中的文件发生变化
WatchKey watchKey = watchService.take();
while(watchKey != null) {
for(WatchEvent<?> event : watchKey.pollEvents()) {
//如果文件发生变化
if(event.kind() == StandardWatchEventKinds.ENTRY_MODIFY && event.context().toString().equals(Paths.get(filePath).getFileName().toString())) {
//读取数据
fr = new FileReader(filePath);
ch = new char[1024];
length = fr.read(ch);
return new String(ch, 0, length);
}
}
watchKey.reset();
watchKey = watchService.take();
}
return null;
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
try {
fr.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
在这个示例代码中,我们创建了一个WatchService实例,并将需要监控的目录注册到WatchService中。当目录中的文件发生变化时,WatchService会接收到通知,我们可以在通知中执行读取数据的代码。注意,我们需要在通知中判断文件是否为需要读取的文件。