Java以任意编码格式加载文本文件
找了很多java文本本文件编码获取的,都不靠谱,最后找到了一个博客java 获取文本文件编码格式可以正常使用,贴在这里以供备忘。
我看到的大多数获取文本文件的编码格式都仅仅是通过读取开头三个字节的数据来判断文本的编码格式,但是经过我的测试,当文本开头为ASCII字符等的时候,无法正确判断出文件所采用的编码格式,我对这个方法的理解为,先通过判断开头的三个字节,如果无法判断则以字节流的形式遍历文件,通过测试每个字节的方式判断编码格式。
/**
* @file FileUtil.java
* @package default
* @author Wagsn
* @date 2018年8月12日
* @version 1.0.0
*/
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import org.junit.Test; // JUint 4 Library
/**
* @class FileUtil
* @author Wagsn
* @date 2018年8月12日
* @version 1.0.0
*/
public class FileUtil {
/**
* 示例文件路径
*/
public static String path = "./files/expression_src.ws";
/**
* JUint 4 单元测试,测试加载方法是否正常
*
* @throws Exception
*/
@Test
public void testLoad() {
System.out.println("--文件-> [" + path + "] 的内容如下:\n" + load(path)); // 在控制台没有打印出换行
}
/**
* 加载文件通过路径从文件系统。
* TODO 将path扩展为URL,并增加路径检查
*
* @param path
* @return
* @throws Exception
*/
public static StringBuffer load(String path) {
StringBuffer buffer = new StringBuffer("");
try {
String code = charset(path);
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(path)), code));
String temp = null;
while ((temp = br.readLine()) != null) {
buffer.append(temp);
}
br.close();
return buffer;
} catch (Exception e) {
System.err.println("--读取文件-> [" + path + "] 失败!");
e.printStackTrace();
}
return buffer; // buffer.length()==0
}
/**
* 判断文本文件的字符集,文件开头三个字节表明编码格式。
* <a href="http://blog.163.com/wf_shunqiziran/blog/static/176307209201258102217810/">参考的博客地址</a>
*
* @param path
* @return
* @throws Exception
* @throws Exception
*/
public static String charset(String path) {
String charset = "GBK";
byte[] first3Bytes = new byte[3];
try {
boolean checked = false;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
bis.mark(0); // 读者注: bis.mark(0);修改为 bis.mark(100);我用过这段代码,需要修改上面标出的地方。
// Wagsn注:不过暂时使用正常,遂不改之
int read = bis.read(first3Bytes, 0, 3);
if (read == -1) {
bis.close();
return charset; // 文件编码为 ANSI
} else if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
charset = "UTF-16LE"; // 文件编码为 Unicode
checked = true;
} else if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {
charset = "UTF-16BE"; // 文件编码为 Unicode big endian
checked = true;
} else if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB
&& first3Bytes[2] == (byte) 0xBF) {
charset = "UTF-8"; // 文件编码为 UTF-8
checked = true;
}
bis.reset();
if (!checked) {
while ((read = bis.read()) != -1) {
if (read >= 0xF0)
break;
if (0x80 <= read && read <= 0xBF) // 单独出现BF以下的,也算是GBK
break;
if (0xC0 <= read && read <= 0xDF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF) // 双字节 (0xC0 - 0xDF)
// (0x80 - 0xBF),也可能在GB编码内
continue;
else
break;
} else if (0xE0 <= read && read <= 0xEF) { // 也有可能出错,但是几率较小
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
read = bis.read();
if (0x80 <= read && read <= 0xBF) {
charset = "UTF-8";
break;
} else
break;
} else
break;
}
}
}
bis.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("--文件-> [" + path + "] 采用的字符集为: [" + charset + "]");
return charset;
}
}