`
lifethinker
  • 浏览: 71820 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

用Java自动检查文件的编码方式

    博客分类:
  • java
阅读更多

大多数文本编辑器在打开文件时都能够自动检测文件的编码,那它是怎样做到的呢?我虽然没有实现过一个文本编辑器,但是可以猜测的是,它有一个默认的编码集合,然后尝试用每一个编码去解码打开的文件,如果能够解码则表示这就是文件的正确编码。有一些特殊情况,有些编码在文件开头有特殊的标记字节,因而可以很快检测,这里不考虑。现在的核心问题就是如何决定一个编码是否能够解码一个文件,在Java1.4中可以利用nio中的Charset来解决这个问题。

 

	/**
	 * 测试输入字节流是否能够使用指定的字符集解码。
	 */
	public static boolean canDecode(InputStream input, Charset charset) throws IOException {
		ReadableByteChannel channel = Channels.newChannel(input);
		CharsetDecoder decoder = charset.newDecoder();

		ByteBuffer byteBuffer = ByteBuffer.allocate(2048);
		CharBuffer charBuffer = CharBuffer.allocate(1024);
	
		boolean endOfInput = false;
		while (!endOfInput) {
			int n = channel.read(byteBuffer);
			byteBuffer.flip(); // flip so it can be drained
			
			endOfInput = (n == -1);
			CoderResult coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);
			charBuffer.clear();
			if (coderResult == CoderResult.OVERFLOW) {
				while (coderResult == CoderResult.OVERFLOW) {
					coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);
					charBuffer.clear();
				}
			}
			if (coderResult.isError()) {
				return false;
			}
			byteBuffer.compact(); // compact so it can be refilled
		}
		CoderResult coderResult;
		while ((coderResult = decoder.flush(charBuffer)) == CoderResult.OVERFLOW) {
			charBuffer.clear();
		}
		if (coderResult.isError()) {
			return false;
		}
		
		return true;
	}

 要理解上面的代码必须熟悉对Buffer和Channel的操作以及解码的过程。上面的代码只是决定能不能解码,下面代码能够解码出的内容写到字符输出流中(也就是Writer),它要更复杂一些。

 

	
	/**
	 * 使用指定的字符集解码字节输入流,并将它写入到字符输出流中,如果发生解码错误则返回false,否则返回true,
	 * 输入中的无效字节序列将被忽略。
	 */
	public static boolean decode(InputStream input, Writer output, Charset charset) throws IOException {
		ReadableByteChannel channel = Channels.newChannel(input);
		CharsetDecoder decoder = charset.newDecoder();

		ByteBuffer byteBuffer = ByteBuffer.allocate(2048);
		CharBuffer charBuffer = CharBuffer.allocate(1024);
	
		boolean endOfInput = false;
		boolean error = false;
		while (!endOfInput) {
			int n = channel.read(byteBuffer);
			byteBuffer.flip(); // flip so it can be drained
			
			endOfInput = (n == -1);
			CoderResult coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);
			error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);
			if (coderResult != CoderResult.UNDERFLOW) {
				while (coderResult != CoderResult.UNDERFLOW) {
					coderResult = decoder.decode(byteBuffer, charBuffer, endOfInput);
					error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);
				}
			}
			byteBuffer.compact(); // compact so it can be refilled
		}
		CoderResult coderResult;
		while ((coderResult = decoder.flush(charBuffer)) != CoderResult.UNDERFLOW) {
			error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);
		}
		error = drainCharBuffer(error, byteBuffer, charBuffer, coderResult, output);
		
		output.flush();
		return !error;
	}
	
	private static boolean drainCharBuffer(boolean error, ByteBuffer byteBuffer, 
			CharBuffer charBuffer, CoderResult coderResult, Writer output) throws IOException {
		// write charBuffer to output
		charBuffer.flip();
		if (charBuffer.hasRemaining())
			output.write(charBuffer.toString());
		charBuffer.clear();
		
		if (coderResult.isError()) {
			error = true;
			byteBuffer.position(byteBuffer.position() + coderResult.length()); // ignore invalid byte sequence
		}
		return error;
	}

 

要注意byteBuffer的大小不能太小以至于比一个字符的最大字节数还要小,比如说utf-8的每个字符最多可能占用4个字节,如果设置byteBuffer的大小为3,解码结果可能总是CoderResult.UNDERFLOW,但是又无法再往byteBuffer填充数据,因而会出现死循环。

 

另外要注意的是,程序可能得到错误的结果,如:

		String s = "abc中国";
		byte[] utf8Bytes = s.getBytes(Charset.forName("utf-8"));
		byte[] gbkBytes = s.getBytes(Charset.forName("gbk"));
		CharArrayWriter writer = new CharArrayWriter();
		System.out.println(decode(new ByteArrayInputStream(utf8Bytes), writer, Charset.forName("utf-8")));
		System.out.println(writer.toString());
		writer = new CharArrayWriter();
		System.out.println(decode(new ByteArrayInputStream(utf8Bytes), writer, Charset.forName("gbk")));
		System.out.println(writer.toString());
 

输出结果:

true
abc中国
true
abc涓浗

 可以看到用utf-8编码的字节流仍然可以用gbk进行解码,但是解码的结果却不对。这是偶然情况,将字符串换成"中国人",则用gbk就不能解码了。

 

 

分享到:
评论
1 楼 zhuhelong520 2013-03-29  
测试输入字节流是否能够使用指定的字符集解码。
这个可能会出现死循环哟
走28行 n值永远不变的话···卡死在里面了

相关推荐

    读取创建CSV文件并自动解析文件编码方式

    本文将深入探讨如何读取和创建CSV文件,并特别关注自动解析文件编码方式这一关键环节。我们将使用Java语言进行示例,同时引入第三方库来辅助处理编码问题。 首先,创建CSV文件的基本过程涉及将数据写入具有特定分隔...

    java 文件编码转换

    标题"java 文件编码转换"指的是使用Java来解决文件编码问题,而描述中提到的"提供一个jar包和一个java文件"则暗示了我们可以通过这两个文件实现这个功能。 首先,`chardet.jar`可能是一个字符集检测库,用于自动...

    解析URL和文件的编码方式

    在处理未知编码的文件时,可能需要使用一些库来自动检测文件的编码,例如ICU4J库提供了`BreakIterator`和`CharsetDetector`类,能够帮助识别文件的编码格式。 了解和熟练掌握URL和文件的编码方式对于开发跨平台、跨...

    java判断文件编码

    `cpdetector`是字符集探测器,它包含多种字符集识别算法,如JChardet(基于Mozilla的开源项目),用于自动检测文件的编码方式。而`chardet.jar`可能就是JChardet的实现,它基于字节序列的概率模型来识别编码。 `...

    java 获取文件编码

    在Java编程语言中,获取文件编码是一个常见的任务,特别是在处理文本文件时,了解正确的编码格式至关重要,因为不同的编码方式会影响字符的表示和解析。本文将深入探讨如何在Java中识别和处理不同类型的文本编码,如...

    java获取文件编码(判断有无BOM)

    文件编码决定了字符集的表示方式,而BOM(Byte Order Mark)则是一种特殊的Unicode标记,用于标识文件的编码类型。本文将详细介绍如何在Java中获取文件的编码并判断文件是否带有BOM。 首先,让我们了解一下什么是...

    Java 自动识别编码

    然而,Java标准库并没有提供一种直接的自动检测文件编码的方法。通常,开发者需要借助第三方库或者自定义算法来实现这个功能。 这篇名为“BytesEncodingDetect.java”的文件很可能包含了一个自定义的编码检测算法。...

    Java自动识别文件字符编码工具类.rar

    Java自动识别文件字符编码工具类 参考博客 https://blog.csdn.net/superbeyone/article/details/103036914 使用方式: String encode = EncodingDetect.getFileEncode(geoJsonFile); log.info("系统检测到文件[ {}...

    JAVA自动获取文件的编码工具类

    例如,在读取文本文件时,我们可以先用`EncodingDetect`检测文件编码,然后使用对应的编码打开文件,避免出现乱码问题。在处理大量未知编码的文件时,这样的工具尤其有用。 为了更好地使用这个工具,开发者需要了解...

    java自动获取文件的编码

    例如,UTF-8是最常见的编码方式,支持全世界大部分语言的字符,而GBK是中国大陆常用的编码,主要针对中文。 Java本身提供了`java.nio.charset.Charset`类来处理字符编码。然而,Java的标准库并不直接提供一种方法来...

    批量编码转化工具(实现文件编码的自动检测)

    批量编码转化工具正是为了解决这一问题而设计的,它能够自动检测文件的编码,并进行相应的转换,确保数据的一致性和可读性。下面将详细介绍这个工具的工作原理、使用方法以及可能涉及的相关技术。 1. 文件编码的...

    java 解析csv文件例子,csv文件 中文乱码问题

    2. **使用`CharsetDetector`**:如果不确定编码,可以使用Apache Commons Lang的`CharsetDetector`或ICU4J库的`CharsetDetector`来自动检测文件编码。 3. **文件头部声明**:某些CSV文件可能包含一个编码声明,如`# ...

    批量转化文件编码工具(附Java源码)

    Java的`Charset`类可以用来识别或指定文件的字符集,例如使用`CharsetDetector`进行自动检测。 3. **BufferedReader和PrintWriter**:在读写过程中,可以使用`BufferedReader`和`PrintWriter`来处理字符流,以减少...

    java读写csv文件,中文乱码问题

    可以使用工具,如Notepad++,来检查和更改文件编码。 4. **处理BOM头**:UTF-8有带BOM和不带BOM两种形式,如果文件开头带有BOM标记,可能需要在读取时进行特殊处理,因为某些库可能不支持带BOM的UTF-8。 5. **使用...

    JAVA文件编码转换

    ### JAVA文件编码转换 #### 知识点概览 1. **文件编码概念与重要性** 2. **Java中的字符集处理** 3. **文件读写操作** 4. **使用NIO进行文件编码转换** 5. **异常处理** #### 文件编码概念与重要性 在计算机科学...

    java源文件编码转换工具加源码(自动检测源文件编码类型)

    用户可以通过下载并运行这个JAR文件来进行文件编码的转换工作。 总的来说,这个工具解决了开发环境中由于源代码编码不一致带来的问题,通过自动化检测和转换,确保了代码的可读性和跨平台兼容性,对于维护大型项目...

    cpdetector.jar java检测文件编码开源jar包

    "cpdetector.jar" 是一个基于Java的开源工具,主要用于检测文件的字符编码。在软件开发过程中,正确识别和处理文件的编码格式至关重要,因为不同的文件可能采用不同的编码标准,如UTF-8、GBK、ISO-8859-1等。如果不...

    java获取字符串编码类型代码(导入直接查看结果)

    一种常见方法是尝试用不同的编码方式解析字符串,观察是否出现乱码。以下是一个简单的示例: ```java import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset....

    Java源码编码转换器 v2.0 GBK TO UTF8

    该转换器不仅提供简单的编码转换功能,还包含了一个名为NChardet的源码,这是一个自动检测文件编码的库。NChardet通常用于识别未知编码的文本文件,它可以分析文件的字节序列并推测出最可能的编码方式。在Java源码...

Global site tag (gtag.js) - Google Analytics