/** * 920 Text Editor is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 920 Text Editor is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 920 Text Editor. If not, see <http://www.gnu.org/licenses/>. */ package com.jecelyin.util; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import jecelyin.android.v2.text.SpannableStringBuilder; import com.jecelyin.editor.JecEditor; import com.stericson.RootTools.RootTools; public class FileUtil { /*** * The number of bytes in a kilobyte. */ public static final double ONE_KB = 1024.0; /*** * The number of bytes in a megabyte. */ public static final double ONE_MB = ONE_KB * ONE_KB; /*** * The number of bytes in a gigabyte. */ public static final double ONE_GB = ONE_KB * ONE_MB; public static final int DEFAULT_BUFFER_SIZE = 1024 * 8; public static final int EOF = -1; /*** * Returns a human-readable version of the file size, where the input * represents a specific number of bytes. * * @param size * the number of bytes * @return a human-readable display value (includes units) */ public static String byteCountToDisplaySize(long size) { return byteCountToDisplaySize((double) size); } public static String byteCountToDisplaySize(double size) { String displaySize; double ret; if ((ret = size / ONE_GB) > 1.0) { displaySize = " G"; } else if ((ret = size / ONE_MB) > 1.0) { displaySize = " M"; } else if ((ret = size / ONE_KB) > 1.0) { displaySize = " KB"; } else { ret = size; displaySize = " B"; } DecimalFormat df = new DecimalFormat("0.00"); return df.format(ret) + displaySize; } /** * By default File#delete fails for non-empty directories, it works like * "rm". We need something a little more brutual - this does the equivalent * of "rm -r" * * @param path * Root File Path * @return true iff the file and all sub files/directories have been removed * @throws FileNotFoundException */ public static boolean remove(File path) { if (path == null || !path.exists()) return false; boolean ret = true; if (path.isDirectory()) { for (File f : path.listFiles()) { ret = ret && remove(f); } } return ret && path.delete(); } public static SpannableStringBuilder readFile(String filename) throws IOException { return readFile(filename, "UTF-8", LineBreak.NORMAL); } /** * 读取整个文件, android默认编码为utf-8,如果文件编码是gbk或其它编码,要是没有指定正确的编码,就会统一当成ut-8编码处理 * * @param filename * 文件名 * @param encoding * 指定文件编码,否则使用系统默认的编码 * @return * @throws IOException */ public static String readFileAsString(String filename, String encoding) throws IOException { return readFileAsString(new File(filename), encoding); } public static String readFileAsString(File filename, String encoding) throws IOException { FileInputStream fis = new FileInputStream(filename); return readFileAsString(fis, encoding); } public static String readFileAsString(InputStream input, String encoding) throws IOException { StringBuilder output = new StringBuilder(); InputStreamReader isr = new InputStreamReader(input, Charset.forName(encoding)); int n = 0; char[] buffer = new char[DEFAULT_BUFFER_SIZE]; while (EOF != (n = isr.read(buffer))) output.append(new String(buffer, 0, n)); if (input != null) input.close(); return output.toString(); } public static SpannableStringBuilder readFile(String filename, String encoding, int lineBreak) throws IOException { return readFile(new File(filename), encoding, lineBreak); } public static SpannableStringBuilder readFile(File filename, String encoding, int lineBreak) throws IOException { FileInputStream fis = new FileInputStream(filename); return readFile(fis, encoding, lineBreak); } public static SpannableStringBuilder readFile(InputStream input, String encoding, int lineBreak) throws IOException { SpannableStringBuilder output = new SpannableStringBuilder(); InputStreamReader isr = new InputStreamReader(input, Charset.forName(encoding)); int n = 0; char[] buffer = new char[DEFAULT_BUFFER_SIZE]; while (EOF != (n = isr.read(buffer))) { if(lineBreak != LineBreak.NORMAL) { output.append(convertLineBreak(buffer, n, lineBreak)); }else{ output.append(new String(buffer, 0, n)); } } if (input != null) input.close(); return output; } private static String convertLineBreak(char[] buffer, int bufferLength, int lineBreak) { char[] buffer2 = new char[bufferLength*2]; int k=0; for(int i=0; i<bufferLength; i++) { if(buffer[i] == '\r') { if(i+1<bufferLength) { if(lineBreak == LineBreak.WIN) { if(buffer[i+1] == '\n'){ buffer2[k] = buffer[i]; buffer2[++k] = buffer[++i]; }else{ buffer2[k] = buffer[i]; buffer2[++k] = '\n'; //补齐\r\n } }else{ if(lineBreak == LineBreak.MAC) buffer2[k] = '\r'; //mac保留这个\r, unix如果下个字符为\n则移除掉它 if(buffer[i+1] == '\n') i++; else if(lineBreak == LineBreak.UNIX) buffer2[k] = '\n'; //replace \r to \n } } }else if(buffer[i] == '\n'){ if(LineBreak.MAC==lineBreak) { buffer2[k] = '\r'; }else if(LineBreak.WIN==lineBreak){ buffer2[k] = '\r'; buffer2[++k] = '\n'; } }else{ buffer2[k] = buffer[i]; } k++; } return new String(buffer2, 0, k); } public static void writeFile(String path, String text) throws IOException { writeFile(path, text, "UTF-8", LineBreak.NORMAL, true); } /** * 写入文件, 需要指定编码 * * @param path * @param text * @param encoding * @return * @throws IOException */ public static boolean writeFile(String path, String text, String encoding, int lineBreak, boolean isRoot) throws IOException { File file = new File(path); String tempFile = JecEditor.TEMP_PATH + "/root_file_buffer.tmp"; String fileString = path; boolean root = false; if (!file.canWrite() && isRoot && RootTools.isAccessGiven()) { // 需要Root权限处理 fileString = tempFile; root = true; } BufferedWriter bw = null; bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileString), encoding)); if(lineBreak == LineBreak.NORMAL) { bw.write(text); }else if(lineBreak == LineBreak.WIN){ bw.write(text.replaceAll("\r\n|\n|\r", "\r\n")); }else if(lineBreak == LineBreak.MAC){ bw.write(text.replaceAll("\r\n|\n", "\r")); }else if(lineBreak == LineBreak.UNIX){ bw.write(text.replaceAll("\r\n|\r", "\n")); } bw.close(); if (root) { RootTools.copyFile(fileString, LinuxShell.getCmdPath(path), true, true); if (RootTools.lastExitCode != 0) return false; new File(tempFile).delete(); } return true; } public static String getExt(String path) { int lastIndex = path.lastIndexOf("."); if (lastIndex == -1) return null; return path.substring(lastIndex + 1).trim().toLowerCase(); } public static ArrayList<File> getFileList(String path, boolean runAtRoot) { ArrayList<File> fileList = new ArrayList<File>(); ArrayList<File> folderList = new ArrayList<File>(); if (runAtRoot == false) { File base = new File(path); File[] files = base.listFiles(); if (files == null) return null; for (File file : files) { if (file.isDirectory()) { folderList.add(file); } else { fileList.add(file); } } } else { /** 带 root */ try { // -1 One column output // -F Append indicator (one of */=@|) to entries * 表示普通的可执行文件; / // 表示目录; @ 表示符号链接;| 表示FIFOs;= 表示套接字 (sockets) ;什么也没有则表示普通文件。 List<String> resultList = RootTools.sendShell("busybox ls -1 " + path, 1000); File file; for (String line : resultList) { if ("".equals(line.trim()) || "0".equals(line.trim())) continue; file = new File(path, line); if (line.endsWith("/") || file.isDirectory()) { folderList.add(file); } else { fileList.add(file); } } } catch (Exception e) { e.printStackTrace(); } } Comparator<File> mComparator = new Comparator<File>() { public int compare(File fl1, File fl2) { return fl1.getName().compareToIgnoreCase(fl2.getName()); } }; // 排序 Collections.sort(fileList, mComparator); Collections.sort(folderList, mComparator); ArrayList<File> list = new ArrayList<File>(); for (File f : folderList) list.add(f); for (File f : fileList) list.add(f); fileList = null; folderList = null; return list; } }