使用iconv命令批量原地转码文件

文章介绍了如何使用iconv命令在Linux系统中批量转换文件编码,特别是针对从Windows上传到Linux后出现乱码的情况。通过find命令结合iconv,可以原地或通过临时目录转换文件编码,如从GB2312转为UTF-8。此外,文章还展示了在编码不一致的环境中,如何使用shell命令进行文件转码,以解决中文乱码问题。
摘要由CSDN通过智能技术生成

使用iconv命令批量原地转码文件

一、iconv简述

​ 日常工作中我们需要将windows生成的文件上传到Linux系统,有时候会因为编码问题出现显示乱码。例如我上传了一个csv文件到Linux服务器上,默认编码为GB2312,在Linux打开则会出现乱码,我们需要将文件进行编码转换。iconv命令对于给定文件把它的内容从一种编码转换成另一种编码。

iconv语法: iconv [OPTION...][FILE…]

参数参数说明
-f, --from-code=NAME指定输入文件编码,把字符从encoding编码开始转换。
-t, --to-code=NAME指定输出文件编码,把字符转换到encoding编码。
-l, --list列出已知的编码字符集合
-o, --output=FILE指定输出文件
-c忽略输出的非法字符

二、iconv原地转码命令

  • 命令一:使用find命令查要转码的文件使用iconv命令进行转码(仅linux系统中可用)
#find进行文件查找,使用-exec sh -c 将结果传递给后面的 iconv命令进行转码
find .  -name "*.java" -exec sh -c "iconv -f GB18030 -t UTF8 {} -o {}" \;
  • 命令二:使用find命令查要转码的文件使用iconv命令进行转码(linux/windows系统均可用)
find .  -name "*.java" -exec bash -c 'mkdir -p temp/$(dirname {}); iconv -f gb2312 -t utf-8 {} > temp/{} && mv temp/{} {}' \; && rm -rf temp

注: 该命令会在当前目录下临时创建temp目录 因此temp目录需要是之前不存在的,如果已经存在,则修改命令中temp为其他名称

三、我工作中遇到的问题

问题场景:

​ 工作中遇到生产环境de系统编码不一致情况,我的程序是UTF-8编码,生成环境一个是GBK一个UTF8,使用locale命令在生产环境下查看系统编码结果如下,所以编码不一致的环境中,生成的文件毫无疑问的就中文乱码了,我尝试了在OutputStreamWriter中设置文件编码格式、在中文处使用new String(str.getBatys(),UTF-8)的方式手动进行utf-8的中文编码,最终还有个别字符乱码,“公司” 显示 “公xE5 x8F?” 终结果都差强人意,最终选择将生产的文件使用iconv命令进行一次转码,殊途同归。


# 不乱码的环境编码是utf-8:
$ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

# 乱码的环境编码为:
$ locale
LANG=zh_CN.GBK
LC_CTYPE="zh_CN.GBK"
LC_NUMERIC="zh_CN.GBK"
LC_TIME="zh_CN.GBK"
LC_COLLATE="zh_CN.GBK"
LC_MONETARY="zh_CN.GBK"
LC_MESSAGES="zh_CN.GBK"
LC_PAPER="zh_CN.GBK"
LC_NAME="zh_CN.GBK"
LC_ADDRESS="zh_CN.GBK"
LC_TELEPHONE="zh_CN.GBK"
LC_MEASUREMENT=zh_CN.GBK"
LC_IDENTIFICATION="zh_CN.GBK"
LC_ALL=

解决方案:

  1. 使用执行shell命令的工具类,将生产的文本进行一次转码(已下均是伪代码,仅供参考)
    @Value("${transcodingSwitch}")
    private Boolean transcodingSwitch; //话单是否需要转码

    @Value("${transcodingBefore}")
    private String transcodingBefore; //话单转码前的编码格式

    @Value("${transcodingLater}")
    private String transcodingLater; //话单转码后的编码格式


	private boolean iconv(String localFilePath, String localFileName) throws IOException, InterruptedException {
  		//拼接iconv转码命令     
 		String iconvCmd = "find " + localFilePath + " -name " + localFileName + " -exec sh -c \"iconv -f " +
          transcodingBefore + " -t " + transcodingLater + " {} -o {}\" \\;";
        return ExecUtils.exec(iconvCmd);
    }

	//测试转码
	public void testIconv(){
  		if (transcodingSwitch) {
            if (!iconv(transferObject.getLocalFilePath(), localFileName))
              logger.error("Error: " + localFileName + "转码失败!!!");
     	}	
	}
  1. 执行shell命令工具类(模板拿来即用)
import org.apache.log4j.Logger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class ExecUtils {
    public static Logger logger = Logger.getLogger(ExecUtils.class);
    private static final ExecutorService THREAD_POOL = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

    public static boolean exec(String cmd) throws IOException, InterruptedException {
        String[] cmds = {"/bin/sh", "-c", cmd};
        Process process = Runtime.getRuntime().exec(cmds);

        //消费正常日志
        StringBuffer result = clearStream(process.getInputStream());
        //消费错误日志
        StringBuffer errorInfo = clearStream(process.getErrorStream());

        //i为返回值,判断是否执行成功
        int i = process.waitFor();
        if (i != 0) {
            return false;
        }
        return true;
    }

    private static StringBuffer clearStream(final InputStream stream) {
        final StringBuffer result = new StringBuffer();
        //处理buffer的线程
        THREAD_POOL.execute(new Runnable() {
            @Override
            public void run() {
                String line;
                BufferedReader in = null;
                try {
                    in = new BufferedReader(new InputStreamReader(stream));
                    while ((line = in.readLine()) != null) {
                        result.append(line).append("\n");
                    }
                } catch (IOException e) {
                    logger.error("error exec shell.", e);
                } finally {
                    if (in != null) {
                        try {
                            in.close();
                        } catch (IOException ignored) {
                        }
                    }
                }
            }
        });
        return result;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值