流程图:
<pre>
final 外部对象操作时:
通过文件名 -- 在map中找到对应 -- 判断是否修改 --否 -- 返回缓存对象
|
是
|
调用reload,根据传入的handler进行reload,更新缓存对象,更新操作时间
</pre>
主要根据的是文件的修改时间,如果本次读取时的修改时间和缓存中的时间相同,则直接返回缓存,否则的话就重新加载文件,更新缓存和时间
重新加载文件的时候需要传入一个 ReloadHandler,以实现更大的灵活性(策略模式),返回一个新的对象并缓存
(待完善:自动清理功能
方案1:FIFO 最简单,但是效率比较低
方案2:访问次数多的留下,少的去掉
方案3:记得大学里编译原理有个更好的方式,忘记了。
)暂时用FIFO
接口:
/**
* 重新加载接口
* @author qihuan
*
*/
public interface ReloadHandler {
/**
* 分析文件
* @return 要缓存的内容
*/
Object processNewCache() throws Exception;
}
缓存类:
/**
* <pre>
* final 外部对象操作时:
* 通过文件名 -- 在map中找到对应 -- 判断是否修改 --否 -- 返回缓存对象
* |
* 是
* |
* 调用reload,根据传入的handler进行reload,更新缓存对象,更新操作时间
* </pre>
* @author qihuan
*/
public class FileCache {
/** 缓存map */
private static Map<String, CacheElement> cacheMap = new HashMap<String, CacheElement>();
private static FileCache fileCache;
private static final int MAX_SIZE = 20;
private Queue<String> fileQueue = new LinkedList<String>();
/**
* 单例,多线程一样自信
*
* @return fileCache单例
*/
public static FileCache getInstance(){
if(null == fileCache){
fileCache = new FileCache();
}
return fileCache;
}
/**
* 获取缓存对象
* 获取缓存,如果文件被修改,则重新加载最近配置,内存中超过20个文件缓存,会自动清理
* @param fileName
* @return
* @throws Exception
*/
public Object getCache(String fileName,ReloadHandler handler) throws Exception{
fileName = fileName.trim();
if(isModified(fileName)){
reLoad(fileName,handler);
}
return cacheMap.get(fileName).getCache();
}
/**
* 重新加载
* @param fileName
* @param handler
* @throws Exception
*/
private void reLoad(String fileName, ReloadHandler handler) throws Exception {
CacheElement ele = cacheMap.get(fileName);
if(null == ele){
//文件没有加载过
ele = new CacheElement();
//设置File对象
ele.setFile(new File(fileName));
cacheMap.put(fileName, ele);
//添加新的缓存,记录到队列中
if(!fileQueue.contains(fileName)){
//如果队列中没记录这个,则试图添加并进行清理
cacheClean();
fileQueue.add(fileName);
}
}
//更新缓存
ele.setCache(handler.processNewCache());
//更新修改时间
ele.setLastEditTime(ele.getFile().lastModified());
}
/**
* 判断是否已经修改
*
* @param diXmlName
* @return
*/
private boolean isModified(String fileName) {
CacheElement cacheElement = cacheMap.get(fileName);
if (null == cacheElement) {
//配置文件没有被加载过
return true;
}
if (cacheElement.getFile().lastModified() != cacheElement.getLastEditTime()) {
//被修改
return true;
}
// 没有变化
return false;
}
/**
* FIFO 清理缓存,
*/
private void cacheClean(){
//缓存超过限制之后,进行清理
if(fileQueue.size() >= MAX_SIZE ){
String fileName = fileQueue.poll();
cacheMap.put(fileName, null);
cacheMap.remove(fileName);
}
}
//私有构造
private FileCache(){}
/**
* 缓存元素
*
* @author qihuan
*/
class CacheElement {
public long lastEditTime;
public File file;
public Object cache;
public long getLastEditTime() {
return lastEditTime;
}
public void setLastEditTime(long lastEditTime) {
this.lastEditTime = lastEditTime;
}
//setters and getters...
}
}
缓存一个文件的测试类:
测试类:
/**
* 每2秒去获取一次缓存日期,如果文件更新了,则会返回新的缓存日期
*/
public class CacheTest {
@Test
public void getFileContent() {
int count = 10;
while (count-- > 0) {
try {
getCache();
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void getCache() throws Exception {
Date date = (Date)FileCache.getInstance().getCache("e:/1.txt", new ReloadHandler() {
@Override
public Object processNewCache() {
System.out.print("find change ");
return new Date();
}
});
System.out.println(date);
}
}
output:
find change Wed Dec 28 15:25:46 CST 2011 (初始化)
Wed Dec 28 15:25:46 CST 2011
Wed Dec 28 15:25:46 CST 2011
Wed Dec 28 15:25:46 CST 2011
Wed Dec 28 15:25:46 CST 2011
find change Wed Dec 28 15:25:56 CST 2011
Wed Dec 28 15:25:56 CST 2011
Wed Dec 28 15:25:56 CST 2011
Wed Dec 28 15:25:56 CST 2011
Wed Dec 28 15:25:56 CST 2011
实际应用时代码片段
/**
* 获取配置
*
* @param diXmlName
* 接口配置文件名称
* @param diXmlPath
* 接口配置文件完整路径
* @return
* @throws DataConfigException
*/
public DataInterfaceConfig getConfig(final String diXmlName) throws DataConfigException {
DataInterfaceConfig config = null;
final String diXmlPath = Constant.CONFIG_HOME + File.separator + "diConfig" + File.separator + diXmlName;
try {
config = (DataInterfaceConfig) FileCache.getInstance().getCache(diXmlPath, new ReloadHandler() {
@Override
public Object processNewCache() throws Exception {
//重新加载配置文件
return DataInterfaceConfigParser.parser(diXmlPath);
}
});
} catch (Exception e) {
throw new DataConfigException(e);
}
return config;
}
/**
* 从缓存中 根据code 获取 接口配置
* @param code
* @return
* @throws BizException
*/
public DataInterface getDataInterfaceByCode(String code) throws BizException{
Map<String,DataInterface> dataInterface = null;
//获取缓存
try {
dataInterface = (Map<String,DataInterface>) FileCache.getInstance().getCache(Constant.CONFIG_HOME + File.separator + Constant.DIGROUP_CONFIG_XML, new ReloadHandler() {
@Override
public Object processNewCache() throws Exception {
return getAllConfigInGroup();
}
});
} catch (Exception e) {
throw new BizException(e);
}
return dataInterface.get(code);
}
分享到:
相关推荐
java实现缓存可以通过读取本地文件的方式实现,改代码就是通过读取本地文件实现缓存的简单例子
Java高速文件缓存是一种优化应用程序性能的技术,它通过将经常访问的数据存储在内存中,以减少对硬盘或网络I/O的依赖,从而显著提高数据读取速度。在Java中实现高效的文件缓存策略,可以利用Java集合框架、内存管理...
Ehcache本身提供了线程安全的保证,但如果是自定义的缓存实现,需要考虑并发读写的问题,可以使用`synchronized`关键字或`java.util.concurrent`包中的工具类。 7. **异常处理**:在处理缓存和数据库查询时,需要...
### Java流(文件读写操作) #### 一、流的分类 Java中处理文件和数据时,使用流的概念来进行操作。根据不同的标准,流可以分为几种类型。 ##### 1. 按数据流动方向 - **输入流**:主要用于从数据源读取数据。输入...
总结来说,Java文件读写涉及到`FileInputStream`、`FileOutputStream`、`InputStreamReader`、`BufferedReader`、`FileWriter`等核心类。正确选择和组合这些类,可以高效地进行文件操作,同时要注意线程安全和性能...
### Java读取SHP文件及DBF属性的关键技术解析 #### 概述 在地理信息系统(GIS)领域,Shapefile是一种常见的矢量数据格式,用于存储地理位置信息及相关属性数据。一个完整的Shapefile由多个文件组成,包括.shp、....
在Java编程语言中,`IO`(Input/Output)是处理数据输入和输出的核心部分,尤其是在处理大数据量文件时显得尤为...通过选择合适的流类型、使用缓冲、合理分块以及考虑异步和并发,可以有效地提高文件读取和处理的性能。
通常,这会涉及到创建一个解析器类,逐行读取DXF文件,根据DXF的语法解析各个部分。 1. **解析过程**: - 文件头部:读取文件的版本信息和其他设置。 - 图层定义:解析图层的颜色、线型、线宽等属性。 - 图形...
本教程将深入讲解如何使用Java读取JSON文件,并将其内容转化为Map以便进行取值操作。 首先,我们需要引入处理JSON的库。Java标准库并不直接支持JSON操作,所以我们通常会使用第三方库,如`org.json`或`...
同时,Java NIO(非阻塞I/O)库提供了`FileChannel`和`ByteBuffer`等类,它们能更高效地处理大文件读取。 在进行文件读取时,需要注意错误处理,如在给定的代码中,使用了`try-catch-finally`块确保资源的正确关闭...
3. **线程安全**:在多线程环境中,SimpleCache 必须确保对缓存的读写操作是安全的,防止数据不一致或竞态条件。 4. **缓存策略**:SimpleCache 可能支持不同的缓存策略,如 LRU(Least Recently Used)最近最少...
7. 错误处理:在整个过程中,需要捕获并处理可能出现的异常,如文件读取错误、数据库连接失败等。 在实际开发中,可能还需要考虑性能优化,例如使用多线程并行处理多个Word文件,或者在数据库端进行批量操作以减少...
下面将详细介绍如何使用Java进行GRIB2文件的读取和解析。 1. **理解GRIB2文件结构**: GRIB2文件由多个消息组成,每个消息包含一组相关的气象数据。消息由一个固定长度的头部(Header)和可变长度的数据部分(Data...
具体内容包括URL、InputStream、BufferedInputStream、HttpURLConnection等类的使用,同时还有多线程控制和网络文件读取的异常处理等方面。 具体到文件中的代码片段和概念,我们可以将其拆解如下: 1. **多线程**...
本项目提供了一个Java实现的Redis缓存工具类,结合SSM框架,可以帮助开发者快速地集成和管理Redis缓存。 首先,让我们了解一下Java中的SSM框架: 1. **Spring**:这是一个全面的开源应用框架,提供了依赖注入(DI)...
例如,`FileInputStream`和`FileOutputStream`用于读写文件,而`BufferedReader`和`PrintWriter`则常用于读取文本文件或向文件写入文本。 4. **多线程**:为了实现文件操作的并行性,开发者可能使用了Java的多线程...
下面将详细介绍Java文件序列化读写的相关知识点。 1. **序列化的目的**: - **持久化对象**:将对象状态保存到文件或数据库中,即使程序关闭,下次启动时仍能恢复。 - **跨网络传输**:在网络通信中,通过序列化...
本文将深入探讨Android中的文件缓存技术,尤其是如何利用文件来存储和读取字符串数据。文件缓存是一种常见的本地缓存策略,它通过将数据持久化到设备的文件系统中,实现数据的快速访问。 首先,我们需要了解Android...
在Java平台上,处理配置文件是开发过程中的常见任务。...综上所述,Java平台可以通过`ini4j`库轻松地读写INI配置文件,无论是本地还是网络上的文件。合理使用这些功能,可以帮助开发者更高效地管理和维护应用的配置。
在上面的代码中,我们使用 HashMap 缓存文件头信息,并使用 FileInputStream 读取文件的二进制数据,将其转换为十六进制字符串。然后,使用缓存的文件头信息来判断文件的真正类型。 在进行文件上传时,可以使用该类...