Java学习笔记-CSV文件的乱码处理

主要是在读取文件的时候指定文件的编码,获取文件编码示例如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

public class FileCharsetUtils {

	public static Logger LOG = LoggerFactory.getLogger(FileCharsetUtils.class);

	public static String getCharset(String filePath) {
		String charset = null;
		try {
			charset = getCharset(new FileInputStream(filePath));
		} catch (FileNotFoundException e) {
			LOG.error(e.getMessage(), e);
		}
		LOG.info("文件[" + filePath + "] 采用的字符集为: [" + charset + "]");
		return charset;
	}

	public static String getCharset(InputStream inputStream) {
		String charset = "GBK";
		byte[] first3Bytes = new byte[3];
		try {
			boolean checked = false;
			BufferedInputStream bis = new BufferedInputStream(inputStream);
			bis.mark(0);
			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) {
			LOG.error(e.getMessage(), e);
		} finally {
			try {
				if (null != inputStream) inputStream.close();
			} catch (IOException e) {
				LOG.error(e.getMessage(), e);
			}
		}
		LOG.info("文件采用的字符集为: [" + charset + "]");
		return charset;
	}

	public static String getCodeString(String fileName) throws Exception {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName));
		int i = (bis.read() << 8) + bis.read();
		bis.close();
		String code = null;
		switch (i) {
			case 0xefbb:
				code = "UTF-8";
				break;
			case 0xfffe:
				code = "Unicode";
				break;
			case 0xfeff:
				code = "UTF-16BE";
				break;
			default:
				code = "GBK";
		}
		return code;
	}

}

读取文件的时候指定编码

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class CsvFileUtils {

	public static Logger LOG = LoggerFactory.getLogger(CsvFileUtils.class);

	public static <T> void read(String filePath, LineHandler lineHandler, Consumer<List<T>> consumer,
			int threshold, int ignoreLineCount) {
		try {
			read(new FileInputStream(new File(filePath)), FileCharsetUtils.getCharset(filePath),
				lineHandler, consumer, threshold, ignoreLineCount);
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		}
	}

	public static <T> void read(InputStream in, LineHandler lineHandler, Consumer<List<T>> consumer,
			int threshold, int ignoreLineCount) {
		read(in, null, lineHandler, consumer, threshold, ignoreLineCount);
	}

	public static <T> void read(InputStream in, String charsetName, LineHandler lineHandler,
			Consumer<List<T>> consumer, int threshold, int ignoreLineCount) {
		List<T> ts = new ArrayList<T>();
		InputStream in1 = null, in2 = null;
		BufferedReader br = null;
		try {
			if (StringUtils.isBlank(charsetName)) {
				ByteArrayOutputStream baos = cloneInputStream(in);
				in1 = new ByteArrayInputStream(baos.toByteArray());
				in2 = new ByteArrayInputStream(baos.toByteArray());
				br = new BufferedReader(new InputStreamReader(in2, FileCharsetUtils.getCharset(in1)));
			} else {
				br = new BufferedReader(new InputStreamReader(in, charsetName));
			}
			for (int i = 0; i < ignoreLineCount; i++)
				br.readLine();
			String line = null;
			while ((line = br.readLine()) != null) {
				ts.add(lineHandler.handle(line));
				if (ts.size() > threshold) {
					consumer.accept(ts);
					ts.clear();
				}
			}
			if (ts.size() > 0) {
				consumer.accept(ts);
				ts.clear();
			}
		} catch (Exception e) {
			LOG.error(e.getMessage(), e);
		} finally {
			try {
				if (null != in) in.close();
				if (null != in1) in1.close();
				if (null != in2) in2.close();
				if (null != br) br.close();
			} catch (Exception e) {
				LOG.error(e.getMessage(), e);
			}
		}
	}

	private static ByteArrayOutputStream cloneInputStream(InputStream inputStream) {
		try {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len;
			while ((len = inputStream.read(buffer)) > -1) {
				baos.write(buffer, 0, len);
			}
			baos.flush();
			return baos;
		} catch (IOException e) {
			LOG.error(e.getMessage(), e);
			return null;
		}
	}

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
文件上传是Web开发中常见的功能之一,Java中也提供了多种方式来实现文件上传。其中,一种常用的方式是通过Apache的commons-fileupload组件来实现文件上传。 以下是实现文件上传的步骤: 1.在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> ``` 2.在前端页面中添加文件上传表单: ```html <form method="post" enctype="multipart/form-data" action="upload"> <input type="file" name="file"> <input type="submit" value="Upload"> </form> ``` 3.在后台Java代码中处理上传文件: ```java // 创建一个DiskFileItemFactory对象,用于解析上传的文件 DiskFileItemFactory factory = new DiskFileItemFactory(); // 设置缓冲区大小,如果上传的文件大于缓冲区大小,则先将文件保存到临时文件中,再进行处理 factory.setSizeThreshold(1024 * 1024); // 创建一个ServletFileUpload对象,用于解析上传的文件 ServletFileUpload upload = new ServletFileUpload(factory); // 设置上传文件的大小限制,这里设置为10MB upload.setFileSizeMax(10 * 1024 * 1024); // 解析上传的文件,得到一个FileItem的List集合 List<FileItem> items = upload.parseRequest(request); // 遍历FileItem的List集合,处理上传的文件 for (FileItem item : items) { // 判断当前FileItem是否为上传的文件 if (!item.isFormField()) { // 获取上传文件文件名 String fileName = item.getName(); // 创建一个File对象,用于保存上传的文件 File file = new File("D:/uploads/" + fileName); // 将上传的文件保存到指定的目录中 item.write(file); } } ``` 以上代码中,首先创建了一个DiskFileItemFactory对象,用于解析上传的文件。然后设置了缓冲区大小和上传文件的大小限制。接着创建一个ServletFileUpload对象,用于解析上传的文件。最后遍历FileItem的List集合,判断当前FileItem是否为上传的文件,如果是,则获取文件名,创建一个File对象,将上传的文件保存到指定的目录中。 4.文件上传完成后,可以给用户一个提示信息,例如: ```java response.getWriter().write("File uploaded successfully!"); ``` 以上就是使用Apache的commons-fileupload组件实现文件上传的步骤。需要注意的是,文件上传可能会带来安全隐患,因此在处理上传的文件时,需要进行严格的校验和过滤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值