package com.persagy.framework.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

/**
 * Description: 文件操作工具类   
 * Company: Persagy 
 * @author cuixubin 
 * @version 1.0
 * @since: 2018年7月11日: 下午4:56:38
 * Update By cuixubin 2018年7月11日: 下午4:56:38
 */
public class FileUtil {
	public static void main(String[] args) throws Exception {
		System.out.println(createFile("d:/test1.json"));
	}
	
	/**
	 * Description: 将字节数组写入到文件
	 * @param fileName 文件名.后缀名
	 * @param data 数据
	 * @return
	 * @throws Exception File
	 * @author cuixubin
	 * @since 2018年9月25日: 上午10:35:41
	 * Update By cuixubin 2018年9月25日: 上午10:35:41
	 */
	public static File writeByteToFile(String fileName, byte[] data) throws Exception {
		String basePath = CommonToolUtils.getFileStorageDictionary();
		basePath += File.separator + "imageServiceSource" + File.separator + fileName;
		File file = createAndGetFile(basePath);
		return writeByteToFile(file, data);
	}
	
	/**
	 * Description: 将字节数据写入到文件 
	 * @param file 目标文件
	 * @param data 数据
	 * @return
	 * @throws Exception File
	 * @author cuixubin
	 * @since 2018年9月25日: 上午10:32:57
	 * Update By cuixubin 2018年9月25日: 上午10:32:57
	 */
	public static File writeByteToFile(File file, byte[] data) throws Exception {
		if(null == file || !file.exists() || file.isDirectory() || data == null) {
			return null;
		}
		
		try(FileOutputStream out = new FileOutputStream(file)) {
			out.write(data);
		}
		
		return file;
	}
	
	/**
	 * Description: 删除目录下的文件及子目录
	 * @param path 目录的绝对路径
	 * @param delFailedFiles 删除失败的文件或文件夹路径信息集合
	 * @return List<String>
	 * @author cuixubin
	 * @since 2018年7月11日: 下午5:20:53
	 * Update By cuixubin 2018年7月11日: 下午5:20:53
	 */
	public static List<String> delDirectory(String path, List<String> delFailedFiles) {
		if(null == delFailedFiles) {
			delFailedFiles = new ArrayList<>();
		}
		
		if(null == path) {
			return delFailedFiles;
		}
		
		File file = new File(path);
		if(file.exists()) {
			if(file.isFile()) {
				file.delete();
			}
			
			if(file.isDirectory()) {
				String[] files = file.list();
				for(String fpath : files) {
					path = path.endsWith(File.separator) ? path : path + File.separator;
					fpath = path + fpath;
					delDirectory(fpath, delFailedFiles);
				}
				file.delete();
			}
			
			delFailedFiles.add(path);
		}
		
		return delFailedFiles;
	}
	
	/**
	 * Description: 读取文件夹下的文件
	 * @param filepath 文件夹绝对路径
	 * @param fileList 存放文件的集合
	 * @return List<File>
	 */
	public static void getFilesInDir(String filepath, List<File> fileList){
		fileList = fileList == null ? new ArrayList<>() : fileList;
		File file = new File(filepath);
		if (!file.isDirectory()) {
			// 是文件
			fileList.add(file);
		} else if (file.isDirectory()) {
			// 是文件夹
			String[] filelist = file.list();
			for (int i = 0; i < filelist.length; i++) {
				File readfile = new File(filepath + File.separator + filelist[i]);
				if (!readfile.isDirectory()) {
					fileList.add(readfile);
				} else if (readfile.isDirectory()) {
					getFilesInDir(filepath + File.separator + filelist[i], fileList);
				}
			}
		}
	}
	
	/**
	 * Description: 根据文件路径创建文件（如果文件所在文件夹不存在则自动创建）,如果所要创建的文件已存在则不创建
	 * @param filePath 路径+文件名+后缀
	 * @return boolean true-创建成功或文件已存在；false-创建失败
	 */
	public static boolean createFile(String filePath) {
		boolean createOK = false;
		
		if(null != filePath) {
			if(filePath.lastIndexOf(File.separator) > 0) {
				String dirPath = filePath.substring(0, filePath.lastIndexOf(File.separator));
				if (dirPath != null && !dirPath.endsWith(":")) {
					createDir(dirPath);
				}
			}
			
			File file = new File(filePath);
			
			if(!file.exists()) {
				try {
					return file.createNewFile();
				} catch (IOException e) {
					e.printStackTrace();
				}
			} else {
				createOK = true;
			}
		}
		
		return createOK;
	}
	
	/**
	 * Description: 根据文件路径创建文件（如果文件所在文件夹不存在则自动创建）,如果所要创建的文件已存在则不创建
	 * @param filePath 路径+文件名+后缀
	 * @return File 创建成功返回文件对象，否则返回null
	 */
	public static File createAndGetFile(String filePath) {
		if(createFile(filePath)) {
			return new File(filePath);
		}
		
		return null;
	}
	
	/**
	 * Description: 根据文件目录和文件名创建文件
	 * @param dirPath 文件目录路径
	 * @param fileName 文件名+后缀
	 * @return boolean 
	 */
	public static boolean createFile(String dirPath, String fileName) {
		boolean createOK = false;
		
		if(createDir(dirPath)) {
			dirPath = dirPath.endsWith(File.separator) ? dirPath : dirPath + File.separator;
			return createFile(dirPath + fileName);
		}
		
		return createOK;
	}
	
	/**
	 * Description: 创建文件夹
	 * @param dirPath 文件夹路径
	 * @return boolean true-创建成功；false-创建失败
	 */
	public static boolean createDir(String dirPath) {
		boolean createOK = false;
		
		if(null != dirPath) {
			File file = new File(dirPath);
			
			if(!file.exists()) {
				return file.mkdirs();
			} else {
				createOK = true;
			}
		}
		
		return createOK;
	}
	
	/**
	 * Description: 删除文件
	 * @param file
	 * @return boolean
	 */
	public static boolean delFile(File file) {
		if(null != file && file.exists() && file.isFile()) {
			return file.delete();
		}
		
		return false;
	}
	
	/**
	 * Description: 删除文件
	 * @param filePath 文件绝对路径
	 * @return boolean true-文件存在且删除成功；false-删除失败
	 */
	public static boolean delFile(String filePath) {
		if(null != filePath) {
			File file = new File(filePath);
			return delFile(file);
		}
		
		return false;
	}
	
	/**
     * 
     * Description: 删除文件夹，及文件夹下的所有子文件夹和文件 
     * @param folderPath void
     */
	public static boolean delFolder(String folderPath) {
		// 删除完里面所有内容 
		if(!delAllFile(folderPath)) {
			return false;
		}
		
        try {  
            String filePath = folderPath.toString();
            File myFilePath = new File(filePath); 
            // 删除空文件夹 
            if(null != myFilePath && myFilePath.exists()) {
            	return myFilePath.delete(); 
            }
        } catch (Exception e) {  
            e.printStackTrace();  
        }
        
        return false;
    }
	
	/**
	 * Description: 删除目录下的所有文件和文件夹
	 * @param path 目录绝对路径
	 * @return boolean true-删除成功；false-删除失败
	 */
	public static  boolean delAllFile(String path) {  
        boolean flag = true; 
        File file = new File(path);  
        if (!file.exists()) {  
            return false;  
        }  
        if (!file.isDirectory()) {  
            return false;  
        }  
        String[] tempList = file.list();  
        File temp = null;  
        for (int i = 0; i < tempList.length; i++) {  
            if (path.endsWith(File.separator)) {  
                temp = new File(path + tempList[i]);  
            } else {  
                temp = new File(path + File.separator + tempList[i]);  
            }  
            if (temp.isFile()) {  
                temp.delete();  
            }  
            if (temp.isDirectory()) {
            	// 先删除文件夹里面的文件
                delAllFile(path + File.separator + tempList[i]);
                // 再删除空文件夹
                delFolder(path + File.separator + tempList[i]);  
            }
        } 
        return flag;  
    }
	
	/**
	 * 使用流拷贝文件，速度慢
	 * @param source 源文件
	 * @param dest 目标文件
	 * @throws IOException
	 */
	public static void copyFile1(File source, File dest) throws IOException {
		InputStream input = null;
		OutputStream output = null;
		try {
			input = new FileInputStream(source);
			output = new FileOutputStream(dest);
			byte[] buf = new byte[1024];
			int bytesRead;
			while ((bytesRead = input.read(buf)) > 0) {
				output.write(buf, 0, bytesRead);
			}
		} finally {
			input.close();
			output.close();
		}
	}

	/**
	 * 使用FileChannel拷贝文件，速度快
	 * @param source 源文件
	 * @param dest 目标文件
	 * @throws IOException
	 */
	public static void copyFile2(File source, File dest) throws IOException {
		try (FileChannel inputChannel = new FileInputStream(source).getChannel();
				FileChannel outputChannel = new FileOutputStream(dest).getChannel();) {
			outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
		}catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 使用Java7的Files类复制文件
	 * @param source 源文件
	 * @param dest 目标文件
	 * @throws IOException
	 */
	public static void copyFile3(File source, File dest) throws IOException {
		Files.copy(source.toPath(), dest.toPath());
	}
	
	/**
	 * Description: 获取文件中内容的总行数 
	 * @param file
	 * @return Integer 文件中内容总行数，默认0行
	 */
	public static Integer getLineNumber(File file) {
		Integer lineNumber = 0;
		
		if(file != null && file.exists() && file.isFile()) {
			try(LineNumberReader lnr = new LineNumberReader(new FileReader(file));) {
				lnr.skip(Long.MAX_VALUE);
				lineNumber = lnr.getLineNumber() + 1;
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		return lineNumber;
	}
	
	/**
	 * Description: 按行读取文件中的信息存入到List集合中
	 * @param file
	 * @return List<String> 文件中的内容，按行存入集合，默认返回空集合
	 */
	public static List<String> readFileToList(File file) {
		List<String> contentList = new ArrayList<>();
		
		if(null == file || !file.exists() || !file.isFile()) {
			return contentList;
		}
		
		try (InputStreamReader isr = new InputStreamReader(new FileInputStream(file));
				BufferedReader br = new BufferedReader(isr);) {
			String temp = null;
			while ((temp = br.readLine()) != null) {
				contentList.add(temp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return contentList;
	}
	
	
	/**
	 * Description: 按行读取文件中的信息，将所读到信息写入到一个字符串当中 
	 * @param file 文件
	 * @return String 文件中的信息
	 * @author cuixubin
	 * @since 2018年7月11日: 下午5:26:35
	 * Update By cuixubin 2018年7月11日: 下午5:26:35
	 */
	public static String readFileToString(File file) {
		StringBuffer sbStr = new StringBuffer();
		List<String> dataStringList = readFileToList(file);
		if(null != dataStringList) {
			for(String str : dataStringList) {
				sbStr.append(str);
			}
		}
		
		return sbStr.toString();
	}
	
	/**
	 * Description: 将字符串写入到指定文件
	 * @param file 已存在的文件绝对路径
	 * @param str 要写入的字符串
	 * @param append true-在文件中追加字符串；false先清空文件中原有内容再写入字符串
	 * @throws Exception void
	 * @author cuixubin
	 * @since 2018年8月19日: 下午8:01:41
	 * Update By cuixubin 2018年8月19日: 下午8:01:41
	 */
	public static void writeInFile(File file, String str, boolean append) throws Exception{
		if(null == file || !file.exists() || !file.isFile()) {
			throw new Exception("文件不存在！");
		}
		
		if(str == null) {
			return;
		}
		
		/*
         try(PrintStream ps = new PrintStream(new FileOutputStream(file));){
        	 if(append) {
        		 ps.append(str);
        	 }else {
        		 ps.println(str);
        	 }
         }
         */

		BufferedWriter out = null;
		try {
			out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, append)));
			out.write(str + "\r\n");
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				out.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

	}
	
}