缓存对象到文件和从文件获取对象

背景


我们在工作中可能会遇到这样的场景,我们需要定时获取获取一个对象。但这个对象比较大,数量比较多。缓存在redis,数据库里面都不太合适。这个时候我们可以考虑将文件缓存本地文件当中。

代码


1、配置文件文件缓存路径
在application.properties中添加

fileCacheDir=C:\\Users\\Administrator\\Desktop\\deploy

2、设置文件缓存路径

@Configuration
public class FileCacheConfig {

    @Value("${fileCacheDir}")
    private String fileCacheDir;


    @Bean
    public FileCache getFileCache(){
       return new FileCache(fileCacheDir);
    }
}

3、操作文件缓存对象

接口

public interface ICache {
    /**
     * 根据key获取缓存数据
     * @param key  存储key
     * @return 缓存到文件中的数据
     */
     T get(String key) throws IOException, ClassNotFoundException, Exception;

    /**
     * 添加缓存
     *   @param key  存储key
     * @param data 缓存到文件中的数据
     */
    int set(String key, Object data) throws IOException;


    /**
     * 删除
     *  @return 删除影响的行数
     */
    int delete(String key);
}

具体操作类:

public class FileCache implements ICache {

    private String cacheDir;

    public FileCache(String cacheDir) {
        this.cacheDir = cacheDir;
    }

    @Override
    public Object get(String key) throws Exception {
        File file = new File(this.getRealFilePath(key));
        if (!file.exists()) {
            return null;
        }
        //获取文件中对象
        Object fileObject = FileOperate.getFileObject(file);
        Object fileStorageObject = null;
        if ( fileObject instanceof FileCacheObject) {
            FileCacheObject fcObject = (FileCacheObject)fileObject;
            //查看缓存是否过期
            if (!fcObject.isCacheExpire()) {
                fileStorageObject = fcObject.getStorageObject();
            }
        }

        //如果不存在活已经过期就删除
        if (null == fileStorageObject) {
            file.delete();
        }
        return fileStorageObject;
    }

    @Override
    public int set(String key, Object data) throws IOException {
        String filePath = this.getRealFilePath(key);
        return FileOperate.saveObjectToFile(filePath, new FileCacheObject(data)) ? 1 : 0;

    }

    @Override
    public int delete(String key) {
        String filePath = this.getRealFilePath(key);
        File file = new File(filePath);
        if (!file.exists()) {
            return 1;
        }else {
            return file.delete() ? 1 : 0;
        }

    }

    /**
     * 获取cache 所存的文件相对路径
     * @param cacheId 缓存id
     */
    protected String getRealFilePath(String cacheId) {
        StringBuilder sb = new StringBuilder(cacheDir);
        if (!cacheDir.endsWith(File.separator)) {
            sb.append(File.separator);
        }
        cacheId = cacheId.toLowerCase();
        sb.append(DigestUtils.md5DigestAsHex(cacheId.getBytes()));
        return sb.toString();
    }
}

4、对接文件和对象转化文件操作类

public class FileOperate {

    public final static String DEFAULT_ENCODING = "UTF-8";

    /**
     * 获取文件路径对应文件对象
     */
    public static Object getFileObject(String filePath) throws IOException, ClassNotFoundException {
        return getFileObject(new File(filePath));
    }


    /**
     * 读取文件中的对象
     */
    public static Object getFileObject(File file) throws IOException, ClassNotFoundException {
        if (!file.exists()) {
            return null;
        }
        try(ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file))){
            return ois.readObject();
        }

    }

    /**
     * 读取文件路劲对应文件的内容
     * @param filePath 文件路径
     * @param encoding 编码格式
     * @return  文件对象
     */
    public static String getFileContent(String filePath,String encoding) throws IOException {
        return getFileContent(new File(filePath), encoding);
    }


    /**
     * 读取文件的文本内容
     */
    public static String getFileContent(File file,String encoding) throws IOException {
        if (!file.exists()) {
            return null;
        }

        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
             ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

            encoding = StringUtils.isEmpty(encoding) ? DEFAULT_ENCODING : encoding;
            int readLen;
            byte[] data = new byte[4096];
            while ((readLen = bis.read(data)) != -1) {
                baos.write(data, 0, readLen);
            }
            return baos.toString(encoding);

        }
    }

    /**
     * 读取文件大小
     */
    public static long getFileLength(File file) throws IOException {
        if (!file.exists()) {
            return 0;
        }
        long total = 0;
        try(FileInputStream fis=new FileInputStream(file)){

            while (true) {
                int expect = fis.available();
                if (expect < 0) {
                    break;
                }
                skip(fis,expect);
                total += expect;
            }
        }
        return total;
    }

    public static void skip(FileInputStream fis, long expect) throws IOException {
        int maxTryTime = 16;
        while (expect > 0 && maxTryTime-- > 0) {
            long current = fis.skip(expect);
            if (current == expect) {
                return;
            }else {
                expect -= current;
            }

        }
    }


    /**
     * 保存内荣到文件
     */
    public static boolean saveContentToFile(String filePath, String content) throws IOException {
        return saveContentToFile(filePath, content, null);
    }

    /**
     * 保存内荣到文件
     */
    public static boolean saveContentToFile(String filePath, String content,String encoding) throws IOException {
        if (StringUtils.isEmpty(encoding)) {
            encoding = DEFAULT_ENCODING;
        }
        return saveContentToFile(filePath, content.getBytes(encoding));
    }

    /**
     * 保存内容到文件
     */
    public static boolean saveContentToFile(String filePath, byte[] data) throws IOException {
        if(!FileOperate.createDir(filePath,true)){
            return false;
        }

        try (FileOutputStream fos = new FileOutputStream(filePath)) {
            fos.write(data);
            fos.flush();
            return true;
        }
    }


    /**
     * 保存对象到文件中
     */
    public static boolean saveObjectToFile(String filePath, Object obj) throws IOException {
        if(!FileOperate.createDir(filePath,true)){
            return false;
        }
        try (ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(filePath))){
            oos.writeObject(obj);
            oos.flush();
            return true;
        }
    }

    /**
     * 创建目录
     */
    public static boolean createDir(String path, boolean isFile) {
        File file = new File(path);
        if (isFile) {
            file = file.getParentFile();
        }

        if (!file.exists()) {
            return file.mkdirs();
        }else {
            return true;
        }

    }
}

5、缓存对象类

@Data
public class FileCacheObject  implements Serializable {
    private static final long serialVersionUID = 908523022948306952L;

    private long createTime;

    private long timeout;

    private Object storageObject;

    public FileCacheObject() {
    }

    public FileCacheObject(Object storageObject) {
        this(Integer.MAX_VALUE, storageObject);
    }

    public FileCacheObject(long timeout, Object storageObject) {
        if (!(storageObject instanceof Serializable)) {
            throw new IllegalArgumentException("storage object must implement Serializable");
        }
        this.createTime = System.currentTimeMillis();
        this.timeout = timeout;
        this.storageObject = storageObject;
    }

    /**
     * 缓存是否过期
     * @return 缓存存是否过期
     */
    public boolean isCacheExpire(){
        //等于0 表示无过期时间
        if (timeout == 0) {
            return false;
        }
        return createTime + timeout < System.currentTimeMillis();
    }


}

7、测试类

@RunWith(SpringRunner.class)
@SpringBootTest
public class FileCacheTest {

    @Resource
    private FileCache fileCache;

    private static final String FILE_CACHE_KEY = "file_cache_key";

    @Test
   public void loadData() throws Exception {
       List users = new ArrayList<>();
       User user1 = User.builder().id(1L).accountBalance(1L).email("email1").headPic("pic1").build();
       User user12 = User.builder().id(2L).accountBalance(2L).email("email2").headPic("pic2").build();
       users.add(user1);
       users.add(user12);
       fileCache.set(FILE_CACHE_KEY, users);

       List userList2= (List)fileCache.get(FILE_CACHE_KEY);
       System.out.println(userList2);

   }
}

打印的具体结果
在这里插入图片描述
缓存在本地文件
在这里插入图片描述

附上User类:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {

    private Long id;

    private String username;

    private String password;

    private String phone;

    private String email;

    private Date created;

    private Date updated;

    private String sourceType;

    private String nickName;

    private String name;

    private String status;

    private String headPic;

    private String qq;

    private Long accountBalance;

    private String isMobileCheck;

    private String isEmailCheck;

    private String sex;

    private Integer userLevel;

    private Integer points;

    private Integer experienceValue;

    private Date birthday;

    private Date lastLoginTime;

}

你可能感兴趣的:(工具类,缓存,文件)