`
请输入用户名
  • 浏览: 46855 次
  • 性别: Icon_minigender_1
  • 来自: martian
社区版块
存档分类
最新评论

java文件读取缓存类

 
阅读更多
流程图:
<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实现缓存可以通过读取本地文件的方式实现,改代码就是通过读取本地文件实现缓存的简单例子

    java高速文件缓存

    Java高速文件缓存是一种优化应用程序性能的技术,它通过将经常访问的数据存储在内存中,以减少对硬盘或网络I/O的依赖,从而显著提高数据读取速度。在Java中实现高效的文件缓存策略,可以利用Java集合框架、内存管理...

    分页缓存

    Ehcache本身提供了线程安全的保证,但如果是自定义的缓存实现,需要考虑并发读写的问题,可以使用`synchronized`关键字或`java.util.concurrent`包中的工具类。 7. **异常处理**:在处理缓存和数据库查询时,需要...

    Java流(文件读写操作)

    ### Java流(文件读写操作) #### 一、流的分类 Java中处理文件和数据时,使用流的概念来进行操作。根据不同的标准,流可以分为几种类型。 ##### 1. 按数据流动方向 - **输入流**:主要用于从数据源读取数据。输入...

    Java文件读写.pdf

    总结来说,Java文件读写涉及到`FileInputStream`、`FileOutputStream`、`InputStreamReader`、`BufferedReader`、`FileWriter`等核心类。正确选择和组合这些类,可以高效地进行文件操作,同时要注意线程安全和性能...

    java读取shp文件代码

    ### Java读取SHP文件及DBF属性的关键技术解析 #### 概述 在地理信息系统(GIS)领域,Shapefile是一种常见的矢量数据格式,用于存储地理位置信息及相关属性数据。一个完整的Shapefile由多个文件组成,包括.shp、....

    java io读取文件

    在Java编程语言中,`IO`(Input/Output)是处理数据输入和输出的核心部分,尤其是在处理大数据量文件时显得尤为...通过选择合适的流类型、使用缓冲、合理分块以及考虑异步和并发,可以有效地提高文件读取和处理的性能。

    java文件读取方法.doc

    同时,Java NIO(非阻塞I/O)库提供了`FileChannel`和`ByteBuffer`等类,它们能更高效地处理大文件读取。 在进行文件读取时,需要注意错误处理,如在给定的代码中,使用了`try-catch-finally`块确保资源的正确关闭...

    java缓存工具 SimpleCache_java_缓存_

    3. **线程安全**:在多线程环境中,SimpleCache 必须确保对缓存的读写操作是安全的,防止数据不一致或竞态条件。 4. **缓存策略**:SimpleCache 可能支持不同的缓存策略,如 LRU(Least Recently Used)最近最少...

    Java读取json文件,并转化为map取值

    本教程将深入讲解如何使用Java读取JSON文件,并将其内容转化为Map以便进行取值操作。 首先,我们需要引入处理JSON的库。Java标准库并不直接支持JSON操作,所以我们通常会使用第三方库,如`org.json`或`...

    java实现读取word文件并且上传到数据库

    7. 错误处理:在整个过程中,需要捕获并处理可能出现的异常,如文件读取错误、数据库连接失败等。 在实际开发中,可能还需要考虑性能优化,例如使用多线程并行处理多个Word文件,或者在数据库端进行批量操作以减少...

    Java读取解析GRIB2文件

    下面将详细介绍如何使用Java进行GRIB2文件的读取和解析。 1. **理解GRIB2文件结构**: GRIB2文件由多个消息组成,每个消息包含一组相关的气象数据。消息由一个固定长度的头部(Header)和可变长度的数据部分(Data...

    用JAVA实现缓冲多线程无阻塞读取远程文件.pdf

    具体内容包括URL、InputStream、BufferedInputStream、HttpURLConnection等类的使用,同时还有多线程控制和网络文件读取的异常处理等方面。 具体到文件中的代码片段和概念,我们可以将其拆解如下: 1. **多线程**...

    Java+redis缓存工具类(SSM)

    本项目提供了一个Java实现的Redis缓存工具类,结合SSM框架,可以帮助开发者快速地集成和管理Redis缓存。 首先,让我们了解一下Java中的SSM框架: 1. **Spring**:这是一个全面的开源应用框架,提供了依赖注入(DI)...

    java 文件管理器

    例如,`FileInputStream`和`FileOutputStream`用于读写文件,而`BufferedReader`和`PrintWriter`则常用于读取文本文件或向文件写入文本。 4. **多线程**:为了实现文件操作的并行性,开发者可能使用了Java的多线程...

    Java 文件 序列化 读写

    下面将详细介绍Java文件序列化读写的相关知识点。 1. **序列化的目的**: - **持久化对象**:将对象状态保存到文件或数据库中,即使程序关闭,下次启动时仍能恢复。 - **跨网络传输**:在网络通信中,通过序列化...

    android缓存技术之文件缓存

    本文将深入探讨Android中的文件缓存技术,尤其是如何利用文件来存储和读取字符串数据。文件缓存是一种常见的本地缓存策略,它通过将数据持久化到设备的文件系统中,实现数据的快速访问。 首先,我们需要了解Android...

    java平台读写ini配置文件(可读网络配置文件)

    在Java平台上,处理配置文件是开发过程中的常见任务。...综上所述,Java平台可以通过`ini4j`库轻松地读写INI配置文件,无论是本地还是网络上的文件。合理使用这些功能,可以帮助开发者更高效地管理和维护应用的配置。

    java实现上传文件类型检测过程解析

    在上面的代码中,我们使用 HashMap 缓存文件头信息,并使用 FileInputStream 读取文件的二进制数据,将其转换为十六进制字符串。然后,使用缓存的文件头信息来判断文件的真正类型。 在进行文件上传时,可以使用该类...

    java 读取服务器上的某个文件,并解决UTF-8 BOM文件的问号问题

    1. **URL和URLConnection**: 要从服务器读取文件,首先需要使用`java.net.URL`类来创建一个URL对象,表示文件的网络位置。然后,通过`openConnection()`方法获取`URLConnection`实例,它可以建立到服务器的连接并...

Global site tag (gtag.js) - Google Analytics