package com.wangyin.ak47.common; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * File-related helper class * * 文件操作工具类 * * @author hannyu * */ public class FileUtil { private static final Logger log = new Logger(FileUtil.class); public static final int READ_BUFFER_SIZE = 1024*8; public static final int MAX_FILE_SIZE = 1024*1024*50; // max 50M // cachedFileMap cache file content // key : fileName (String) // value: // list[0] : lastTs (Long) // list[1] : data (byte[]) private static Map<String, List<Object>> cachedFileMap = new HashMap<String, List<Object>>(); /** * Read file to a single string, and cached it in mem, using UTF-8 encoding. * * Check the 'lastModified' time of data file whenever call, * if changed, re-read it from disk, otherwise return the cached copy in mem. * * 读取文件并缓存到内存中,每次读取检查lastModifed时间,若有修改则重新读取,若无修改则直接返回缓存中的数据。 * * @param filePath * @return * @throws IOException */ public static String readStringCached(String filePath) throws IOException { return readStringCached(filePath, Ak47Constants.DEFAULT_ENCODING); } /** * Read file to a single string, and cached it in mem, using given encoding. * * Check the 'lastModified' time of data file whenever call, * if changed, re-read it from disk, otherwise return the cached copy in mem. * * 读取文件并缓存到内存中,每次读取检查lastModifed时间,若有修改则重新读取,若无修改则直接返回缓存中的数据。 * * @param filePath * @param encoding * @return * @throws IOException */ public static String readStringCached(String filePath, String encoding) throws IOException { return new String(readBytesCached(filePath), encoding); } /** * Read file to a byte array, and cached it in mem, using UTF-8 encoding. * * Check the 'lastModified' time of data file whenever call, * if changed, re-read it from disk, otherwise return the cached copy in mem. * * 读取文件并缓存到内存中,每次读取检查lastModifed时间,若有修改则重新读取,若无修改则直接返回缓存中的数据。 * * * @param filePath * @return * @throws IOException */ public static byte[] readBytesCached(String filePath) throws IOException { File file = new File(filePath); long nowTs = file.lastModified(); if( 0 == nowTs ){ log.warn("{} NOT exist.", filePath); return new byte[0]; } List<Object> fileInfo = cachedFileMap.get(filePath); long lastTs = (null == fileInfo) ? 0L : (Long)fileInfo.get(0); if( nowTs > lastTs ){ log.debug("'{}' NOT cached, really read.", filePath); byte[] bytes = readByteArray(file); fileInfo = new ArrayList<Object>(2); fileInfo.add(Long.valueOf(nowTs)); fileInfo.add(bytes); cachedFileMap.put(filePath, fileInfo); return bytes; }else{ log.debug("read '{}' from cached.", filePath); return (byte[]) fileInfo.get(1); } } /** * Compare the create time of copy in mem with the 'lastModified' time of the file. * * 检查fileName的内容相对于缓存是否改变,通过check lastModifed 来判断。 * * @param filePath * @return */ public static boolean isCachedChanged(String filePath) { File file = new File(filePath); long nowTs = file.lastModified(); List<Object> fileInfo = cachedFileMap.get(filePath); long lastTs = (null == fileInfo) ? 0L : (Long)fileInfo.get(0); return nowTs > lastTs; } /** * Read all the file content to a single string, using UTF-8 encoding. * * 将文件全部读入为字符串,默认编码UTF-8 * * @param filePath 文件名 * @return * @throws IOException */ public static String readString(String filePath) throws IOException { return readString(filePath, Ak47Constants.DEFAULT_ENCODING); } /** * Read all the file content to a single string, using given encoding. * * 将文件全部读入为字符串,需指定编码 * * @param filePath 文件路径 * @param encoding 必须指定编码 * @return * @throws IOException */ public static String readString(String filePath, String encoding) throws IOException{ byte[] bytes = readByteArray(filePath); return new String(bytes, encoding); } /** * Read all the file content to a single string, using given encoding. * * 将文件全部读入为字符串,需指定编码 * * @param file 文件 * @param encoding 必须指定编码 * @return * @throws IOException */ public static String readString(File file, String encoding) throws IOException{ byte[] bytes = readByteArray(file); return new String(bytes, encoding); } /** * Read all the file content to a byte array. * * 将文件全部读入为字节数组 * 若文件不存在或内容为空,则返回 数组长度为0,注意不是null。 * * @param filePath * @return * @throws FileNotFoundException */ public static byte[] readByteArray(String filePath) throws IOException{ File file = new File(filePath); return readByteArray(file); } /** * Read all the file content to a byte array. * * @param file * @return * @throws IOException */ public static byte[] readByteArray(File file) throws IOException{ ByteArrayOutputStream bos = new ByteArrayOutputStream(); if( file.exists() ){ if( file.length() > MAX_FILE_SIZE ){ throw new IOException(file.getName() + " is too large."); } FileInputStream fis = new FileInputStream(file); try{ byte[] buffer = new byte[READ_BUFFER_SIZE]; int read = 0; while ( (read = fis.read(buffer)) != -1 ) { bos.write(buffer, 0, read); } }finally{ fis.close(); } }else{ log.warn("{} NOT exist.", file.getName()); } return bos.toByteArray(); } /** * Writes the a string to a file, append or not. * * 将字符串写入文件,默认编码UTF-8 * * @param filePath 文件名 * @param append 是否追加 * @param content 写入内容 * @throws IOException */ public static void writeString(String filePath, boolean append, String content) throws IOException{ writeString(filePath, append, content, "UTF-8"); } /** * Writes the a string to a file, append or not. * * 将字符串写入文件,需指定编码 * * @param filePath 文件名 * @param append 是否追加 * @param content 写入内容 * @param encoding 编码 * @throws IOException */ public static void writeString(String filePath, boolean append, String content, String encoding) throws IOException{ writeBytes(filePath, append, content.getBytes(encoding)); } /** * Writes a byte array to a file. * * 将字节数组写入文件 * * @param filePath 文件名 * @param append 是否追加 * @param content 写入内容 * @throws IOException */ public static void writeBytes(String filePath, boolean append, byte[] content) throws IOException{ FileOutputStream fos = new FileOutputStream(filePath, append); try{ fos.write(content); fos.flush(); }finally{ fos.close(); } } }