Java文件编码转换工具

                                                           Java文件编码转换工具   

        由于每个人的项目源码的编码设置不同,造成版本库上的代码下载下来之后中文出现乱码,可以单独在Eclipse里面对每个文件更改编码方式,然后拷贝出内容,在恢复成原来的编码,然后再粘贴内容,就可以去除乱码,但是这样做很麻烦。空闲之余,本人写了个批量转码的工具。

        转码实现主要用到 jdk 中的 CharsetEncoder 和 CharsetDecoder.下面贴上代码:

 

/**

 * 实施转码操作

 * @author 储玉庭

 */

public class ChannelIO {

private ReadableByteChannel channelIn;

private WritableByteChannel channelOut;

private CharsetEncoder encoder;

private CharsetDecoder decoder;

private ByteBuffer buffer = ByteBuffer.allocateDirect(1024);

private Stack<Byte> reservedBytes = new Stack<Byte>();

private ByteBuffer swapSpace;

private boolean eof;

 

public ChannelIO(ReadableByteChannel in, WritableByteChannel out,

CharsetEncoder encoder, CharsetDecoder decoder) {

this.channelIn = in;

this.channelOut = out;

this.encoder = encoder;

this.decoder = decoder;

}

 

public void reset(ReadableByteChannel in, WritableByteChannel out,

CharsetEncoder encoder, CharsetDecoder decoder) {

this.channelIn = in;

this.channelOut = out;

this.encoder = encoder;

this.decoder = decoder;

}

 

public void reset() {

eof = false;

this.channelIn = null;

this.channelOut = null;

this.encoder = null;

this.decoder = null;

reservedBytes.clear();

buffer.clear();

if (null != swapSpace)

{

swapSpace.clear();

}

}

 

public void transfer() throws IOException {

long bytesRead = 0;

long tmpBytesRead = 0;

buffer.clear();

while ((tmpBytesRead = fillInBuffer(buffer)) != -1) {

buffer.flip();

byte[] data = encodeLoop(buffer);

channelOut.write(ByteBuffer.wrap(data));

bytesRead += data.length;

buffer.clear();

}

}

 

private int fillInBuffer(ByteBuffer buffer) throws IOException {

int totalBytesRead = 0;

while (!reservedBytes.isEmpty()) {

buffer.put(reservedBytes.pop());

totalBytesRead++;

}

 

int bytesRead = channelIn.read(buffer);

if (-1 != bytesRead) {

totalBytesRead += bytesRead;

} else {

eof = true;

}

 

if (totalBytesRead == 0)

totalBytesRead = -1; // indicates end of file

return totalBytesRead;

}

 

private byte[] encodeLoop(ByteBuffer bufferData)

throws CharacterCodingException {

CoderResult result = null;

ByteBuffer tmpBuffer = null;

int dataLimit = bufferData.limit();

int preferedSize = dataLimit;

boolean exceptionOccurrerd;

do {

try {

exceptionOccurrerd = false;

CharBuffer cBuffer = decoder.decode(bufferData);

bufferData.flip();

tmpBuffer = allocateBuffer(cBuffer, preferedSize);

result = encoder.encode(cBuffer, tmpBuffer, eof);

tmpBuffer.flip();

preferedSize = preferedSize * 3 / 2;

} catch (Exception e) {

reservedBytes.push(bufferData.get(dataLimit - 1));

bufferData.position(dataLimit - 1);

bufferData.flip();

decoder.reset();

dataLimit = dataLimit - 1;

exceptionOccurrerd = true;

}

} while (null != result && result.isOverflow() || exceptionOccurrerd);

 

byte[] data = new byte[tmpBuffer.limit()];

tmpBuffer.get(data);

return data;

}

 

private ByteBuffer allocateBuffer(CharBuffer cBuffer, int preferedSize) {

int totalChars = cBuffer.limit();

int requiredSize = Math.max(

(int) (totalChars * encoder.averageBytesPerChar()),

preferedSize);

if (null == swapSpace || swapSpace.capacity() < requiredSize) {

swapSpace = ByteBuffer.allocate(requiredSize);

}

swapSpace.clear();

return swapSpace;

}

}

 

/**

 * 扫描目录下的所有源码,并调用ChannelIO实施转码

 * @author 储玉庭

 */

public class Convertor {

private static ChannelIO transfer = new ChannelIO(null, null, null, null);

private File rootDir;

private String srcEncoding;

private String destEncoding;

 

public Convertor(File srcDir, String sourceEncoding, String destEncoding)

throws IOException {

if (null == srcDir || !srcDir.exists() || !srcDir.isDirectory()) {

throw new IOException(

"Please specify an existing source file directory!");

}

this.rootDir = srcDir;

this.srcEncoding = sourceEncoding;

this.destEncoding = destEncoding;

}

 

public final void convert(File[] files) throws IOException {

 

for (File srcFile : files) {

try {

convert(srcFile);

} catch (IOException e) {

               System.err.println("Error occurred while convering file: [" + srcFile + "]");

}

}

}

 

public final void convert(File file) throws IOException {

if (null == file || !file.exists()) {

throw new IOException("File [" + file.getCanonicalPath()

+ "] does not exist");

}

 

if (file.isDirectory()) {

convert(file.listFiles());

}

 

if (!file.getName().endsWith(".java")) {

return;

}

 

File tmpFile = new File(file.getCanonicalPath() + ".tmp");

 

ReadableByteChannel channelIn = null;

WritableByteChannel channelOut = null;

boolean succ = false;

try {

channelIn = getChannelForRead(file);

channelOut = getChannelForWrite(tmpFile);

transfer.reset(channelIn, channelOut,

EncodingUtil.getEncoder(destEncoding),

EncodingUtil.getDecoder(srcEncoding));

transfer.transfer();

succ = true;

} finally {

closeChannel(channelIn);

closeChannel(channelOut);

transfer.reset();

if (succ) {

file.delete();

tmpFile.renameTo(file);

}

}

}

 

private static final void closeChannel(Channel channel) {

if (null != channel) {

try {

channel.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

 

private static final ReadableByteChannel getChannelForRead(File file)

throws FileNotFoundException {

return new FileInputStream(file).getChannel();

}

 

private static final WritableByteChannel getChannelForWrite(File file)

throws FileNotFoundException {

return new FileOutputStream(file).getChannel();

}

 

public static void main(String[] args) throws IOException {

if (null == args || args.length < 3) {

System.err

.println("Usage: java Convertor <File Dir> <source encoding> <target encoding>");

System.exit(-1);

}

 

Convertor convertor = new Convertor(new File(args[0]), args[1], args[2]);

convertor.convert(convertor.rootDir.listFiles());

}

}

 

/**

 * 缓存 CharsetEncoder 和 CharsetDecoder

 * @author 储玉庭

 */

public class EncodingUtil {

 

private static final Map<String, CacheEntry<Charset>> charsetCache = new WeakHashMap<String, CacheEntry<Charset>>(

5);

 

public static CharsetEncoder getEncoder(String destEncoding) {

Charset cs = findFromCache(destEncoding);

return cs.newEncoder().onMalformedInput(CodingErrorAction.REPORT)

.onUnmappableCharacter(CodingErrorAction.REPORT);

}

 

public static CharsetDecoder getDecoder(String sourceEncoding) {

Charset cs = findFromCache(sourceEncoding);

return cs.newDecoder().onMalformedInput(CodingErrorAction.REPORT)

.onUnmappableCharacter(CodingErrorAction.REPORT);

}

 

private static Charset findFromCache(String encodingName) {

synchronized (charsetCache) {

CacheEntry<Charset> entry = charsetCache.get(encodingName);

if (null == entry) {

entry = new CacheEntry<Charset>();

entry.name = encodingName;

entry.value = Charset.forName(encodingName);

charsetCache.put(encodingName, entry);

}

return entry.value;

}

}

 

private static final class CacheEntry<V> {

private String name;

private V value;

 

public String name() {

return name;

}

 

public V value() {

return value;

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值