java之的读取文件大全

使用java进行文件读写,因为使用的频率不高,加上写起来也没那么简单,经常容易忘记,然后就得去翻阅以前的笔记,或者找寻之前写的文件读写代码,这次决定好好的整理下这块的知识点,并写几个通用的工具类,简化文件读写的操作

本篇博文将以下面几个点作为研究对象

文件类型

  • 普通文件读写
  • json文件读写
  • csv文件读写
  • xml文件读写
  • ini文件读写
  • properties文件读写
  • yaml 文件读写

读取方式

  • 相对路径
  • 绝对路径
  • 互联网
  • jar包文件读取

编码

  • 编码格式

1. 读写类介绍

java读写文件的IO流分两大类,字节流和字符流,基类分别是字符:Reader和Writer;字节:InputStream和OutPutStream

字符流分为FileReader和FileWrtier,这两个的父类是InputStreamReader和OutStreamWrtier

字节流分为FileInputStream和FileOutPutStream

继承关系表

Reader->InputStreamReader->FileReader

Reader->BufferedReader


Writer->OutputStreamWriter->FileWriter

Writer->BufferedWriter



InputStream->FileInputStream。FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。

InputStream->FilterInputStream->BufferedInputStream


OutputStream->FileOutputStream。FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter

OutputStream->FilterOutputStream->BufferedOutputStream
Reader->InputStreamReader->FileReader

Reader->BufferedReader


Writer->OutputStreamWriter->FileWriter

Writer->BufferedWriter



InputStream->FileInputStream。FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。

InputStream->FilterInputStream->BufferedInputStream


OutputStream->FileOutputStream。FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter

OutputStream->FilterOutputStream->BufferedOutputStream

一般使用流程

  1. 创建文件对象 ​​File file = new File("xxx.txt");​
  2. 用流装载文件 ​​FileReader fr = new FileReader(file);​
  3. 如果用缓冲区,则用缓冲区装载流,用缓冲区是为了提高读写性能 ​​BufferReader br = new BufferReader(fr);​
  4. 开始读写操作 ​​String s = null; StringBuffer sb = new StringBuffer(); while((s=br.readLine()!=null) { sb.append(s); }​
  • 如果遇到字节流要转换成字符流,则在缓冲区前加一步 ​​InputStreamReader isr = new InpuStreamReader(InputStream in);​
  • 需要编码转换的,则在缓冲区前加一步 ​​InputStreamReader isr = new InpuStreamReader(InputStream in,Charset cs);​

2. 读取文件的几种方式

按字节读取文件, 按字符读取文件, 按行读取文件, 随机读取文件

/** * 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。 * * @param fileName *            文件的名 */public static InputStream createByteRead(String fileName) throws IOException {   File file = new File(fileName);   return new FileInputStream(file);
}/** * 以字符为单位读取文件,常用于读文本,数字等类型的文件 * * @param fileName * 文件名 */public static Reader createCharRead(String fileName) throws FileNotFoundException { File file = new File(fileName); return new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
}/** * 以行为单位读取文件,常用于读面向行的格式化文件 * * @param fileName * 文件名 */public static BufferedReader createLineRead(String fileName) throws FileNotFoundException { File file = new File(fileName);// return new BufferedReader(new FileReader(file));
return new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")));
}
/** * 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。 * * @param fileName * 文件的名 */public static InputStream createByteRead(String fileName) throws IOException { File file = new File(fileName); return new FileInputStream(file);
}/** * 以字符为单位读取文件,常用于读文本,数字等类型的文件 * * @param fileName * 文件名 */public static Reader createCharRead(String fileName) throws FileNotFoundException { File file = new File(fileName); return new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
}/** * 以行为单位读取文件,常用于读面向行的格式化文件 * * @param fileName * 文件名 */public static BufferedReader createLineRead(String fileName) throws FileNotFoundException { File file = new File(fileName);// return new BufferedReader(new FileReader(file));
return new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")));
}

上面的方法,主要对读字节,读字符,读行进行简单包装,随机读直接用​​RandomAccessFile​​直接测试用例中给出

/**     * 字节方式读取文件     *     * @throws IOException     */
@Test
public void testByteRead() throws IOException {
String fileName = "/tmp/test.d";
InputStream in = FileUtil.createByteRead(fileName); int temp; while ((temp = in.read()) != -1) {
logger.info("read bytes: {}", temp);
} in.close(); // 关闭输入流


in = FileUtil.createByteRead(fileName); byte[] tmpAry = new byte[100]; while ((temp = in.read(tmpAry)) != -1) {
logger.info("read 100 bytes: {}, return: {}", tmpAry, temp);
} in.close();
} @Test
public void testCharRead() throws IOException {
String fileName = "/tmp/test.d";
Reader reader = FileUtil.createCharRead(fileName); int temp; while ((temp = reader.read()) != -1) {
logger.info("read char: {}", (char) temp);
}
reader.close();


reader = FileUtil.createCharRead(fileName); char[] tmpAry = new char[100]; while ((temp = reader.read(tmpAry)) != -1) {
logger.info("read 100 chars: {}, return: {}", tmpAry, temp);
}
reader.close();
} @Test
public void testLineRead() throws IOException {
String fileName = "/tmp/test.d";
BufferedReader bufferedReader = FileUtil.createLineRead(fileName);
String temp; while ((temp = bufferedReader.readLine()) != null) { // 会过滤掉换行符
logger.info("read line: >>>{}<<<", temp);
}
bufferedReader.close();
} /**
* 随机读取文件内容
*
* 文件名
*/
@Test
public void testRandomRead() {
String fileName = "/tmp/test.d";
RandomAccessFile randomFile = null; try {
System.out.println("随机读取一段文件内容:"); // 打开一个随机访问文件流,按只读方式
randomFile = new RandomAccessFile(fileName, "r"); // 文件长度,字节数
long fileLength = randomFile.length(); // 读文件的起始位置
int beginIndex = (fileLength > 4) ? 4 : 0; // 将读文件的开始位置移到beginIndex位置。
randomFile.seek(beginIndex); byte[] bytes = new byte[10]; int byteread = 0; // 一次读10个字节,如果文件内容不足10个字节,则读剩下的字节。
// 将一次读取的字节数赋给byteread
while ((byteread = randomFile.read(bytes)) != -1) {
System.out.write(bytes, 0, byteread);
}
} catch (IOException e) {
e.printStackTrace();
} finally { if (randomFile != null) { try {
randomFile.close();
} catch (IOException e1) {
}
}
}
}
/** * 字节方式读取文件 * * @throws IOException */
@Test
public void testByteRead() throws IOException {
String fileName = "/tmp/test.d";
InputStream in = FileUtil.createByteRead(fileName); int temp; while ((temp = in.read()) != -1) {
logger.info("read bytes: {}", temp);
} in.close(); // 关闭输入流


in = FileUtil.createByteRead(fileName); byte[] tmpAry = new byte[100]; while ((temp = in.read(tmpAry)) != -1) {
logger.info("read 100 bytes: {}, return: {}", tmpAry, temp);
} in.close();
} @Test
public void testCharRead() throws IOException {
String fileName = "/tmp/test.d";
Reader reader = FileUtil.createCharRead(fileName); int temp; while ((temp = reader.read()) != -1) {
logger.info("read char: {}", (char) temp);
}
reader.close();


reader = FileUtil.createCharRead(fileName); char[] tmpAry = new char[100]; while ((temp = reader.read(tmpAry)) != -1) {
logger.info("read 100 chars: {}, return: {}", tmpAry, temp);
}
reader.close();
} @Test
public void testLineRead() throws IOException {
String fileName = "/tmp/test.d";
BufferedReader bufferedReader = FileUtil.createLineRead(fileName);
String temp; while ((temp = bufferedReader.readLine()) != null) { // 会过滤掉换行符
logger.info("read line: >>>{}<<<", temp);
}
bufferedReader.close();
} /**
* 随机读取文件内容
*
* 文件名
*/
@Test
public void testRandomRead() {
String fileName = "/tmp/test.d";
RandomAccessFile randomFile = null; try {
System.out.println("随机读取一段文件内容:"); // 打开一个随机访问文件流,按只读方式
randomFile = new RandomAccessFile(fileName, "r"); // 文件长度,字节数
long fileLength = randomFile.length(); // 读文件的起始位置
int beginIndex = (fileLength > 4) ? 4 : 0; // 将读文件的开始位置移到beginIndex位置。
randomFile.seek(beginIndex); byte[] bytes = new byte[10]; int byteread = 0; // 一次读10个字节,如果文件内容不足10个字节,则读剩下的字节。
// 将一次读取的字节数赋给byteread
while ((byteread = randomFile.read(bytes)) != -1) {
System.out.write(bytes, 0, byteread);
}
} catch (IOException e) {
e.printStackTrace();
} finally { if (randomFile != null) { try {
randomFile.close();
} catch (IOException e1) {
}
}
}
}

test.d 文件内容如下

he你好
world
he你好
world

上面的输出如下

// 按字节读取10:47:56.754 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 10410:47:56.773 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 10110:47:56.775 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 22810:47:56.781 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 18910:47:56.783 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 16010:47:56.783 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 22910:47:56.785 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 16510:47:56.786 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 18910:47:56.787 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 1010:47:56.787 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 11910:47:56.789 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 11110:47:56.790 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 10810:47:56.792 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 11410:47:56.794 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 10010:47:56.794 [main] INFO  c.h.h.q.file.test.FileUtilTest - read bytes: 1010:47:56.794 [main] INFO  c.h.h.q.file.test.FileUtilTest - read 100 bytes: [104, 101, -28, -67, -96, -27, -91, -67, 10, 119, 111, 108, 114, 100, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], return: 15// 按字符读取10:47:56.721 [main] INFO  c.h.h.q.file.test.FileUtilTest - read char: h10:47:56.736 [main] INFO  c.h.h.q.file.test.FileUtilTest - read char: e10:47:56.736 [main] INFO  c.h.h.q.file.test.FileUtilTest - read char: 你10:47:56.737 [main] INFO  c.h.h.q.file.test.FileUtilTest - read char: 好10:47:56.737 [main] INFO  c.h.h.q.file.test.FileUtilTest - read char: 

10:47:56.737 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: w10:47:56.738 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: o10:47:56.739 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: l10:47:56.743 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: r10:47:56.747 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: d10:47:56.747 [main] INFO c.h.h.q.file.test.FileUtilTest - read char:

10:47:56.748 [main] INFO c.h.h.q.file.test.FileUtilTest - read 100 chars: [h, e, 你, 好,
, w, o, l, r, d, , , , , , , , , , , , , , , , , , , , , , , ], return: 11// 按行读取10:47:56.801 [main] INFO c.h.h.q.file.test.FileUtilTest - read line: >>>he你好<<<10:47:56.803 [main] INFO c.h.h.q.file.test.FileUtilTest - read line: >>>wolrd<<<// 随机读取随机读取一段文件内容:
�好
wolrd
// 按字节读取10:47:56.754 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 10410:47:56.773 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 10110:47:56.775 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 22810:47:56.781 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 18910:47:56.783 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 16010:47:56.783 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 22910:47:56.785 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 16510:47:56.786 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 18910:47:56.787 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 1010:47:56.787 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 11910:47:56.789 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 11110:47:56.790 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 10810:47:56.792 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 11410:47:56.794 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 10010:47:56.794 [main] INFO c.h.h.q.file.test.FileUtilTest - read bytes: 1010:47:56.794 [main] INFO c.h.h.q.file.test.FileUtilTest - read 100 bytes: [104, 101, -28, -67, -96, -27, -91, -67, 10, 119, 111, 108, 114, 100, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], return: 15// 按字符读取10:47:56.721 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: h10:47:56.736 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: e10:47:56.736 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: 你10:47:56.737 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: 好10:47:56.737 [main] INFO c.h.h.q.file.test.FileUtilTest - read char:

10:47:56.737 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: w10:47:56.738 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: o10:47:56.739 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: l10:47:56.743 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: r10:47:56.747 [main] INFO c.h.h.q.file.test.FileUtilTest - read char: d10:47:56.747 [main] INFO c.h.h.q.file.test.FileUtilTest - read char:

10:47:56.748 [main] INFO c.h.h.q.file.test.FileUtilTest - read 100 chars: [h, e, 你, 好,
, w, o, l, r, d, , , , , , , , , , , , , , , , , , , , , , , ], return: 11// 按行读取10:47:56.801 [main] INFO c.h.h.q.file.test.FileUtilTest - read line: >>>he你好<<<10:47:56.803 [main] INFO c.h.h.q.file.test.FileUtilTest - read line: >>>wolrd<<<// 随机读取随机读取一段文件内容:
�好
wolrd

小结:

从上面的三中方式可以较明显的感知到,使用不同的读取类,获取的方式也将不同

  1. ​FileInputStream​​ 二进制的读写
  2. ​InputStreamReader​​ 字符的读写
  3. ​BufferedReader​​ 字符读写,支持按行读取

FileReader 和 InputStreamReader

  • ​FileReader​​​继承了​​InputStreamReader​​,但并没有实现父类中带字符集参数的构造函数,所以使用​​FileReader​​时,可能造成中文乱码,而使用​​InputStreamReader​​则可以根据 ​​new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));​​ 来强制指定编码
  • ​FileReader​​​是字符流,用于从文件中读取数据,​​InputStreamReader​​是转换流,可以把字节转换成字符流的方式读入

2. 读取方式

相对路径获取文件, 绝对路径获取文件, 从网络上获取文件

绝对路径读取

File file = new File(fileName);
File file = new File(fileName);

相对路径读取

InputStream stream = XXX.class.getClassLoader().getResourceAsStream(fileName);
InputStream stream = XXX.class.getClassLoader().getResourceAsStream(fileName);

网络读取

URL url = new URL(fileName);InputStream stream = url.openStream();
URL url = new URL(fileName);InputStream stream = url.openStream();

简单的封装类

public static InputStream getStreamByFileName(String fileName) throws IOException {   if (fileName == null) {       throw new IllegalArgumentException("fileName should not be null!");
} if (fileName.startsWith("http")) { // 网络地址
URL url = new URL(fileName); return url.openStream();
} else if (fileName.startsWith("/")) { // 绝对路径
Path path = Paths.get(fileName); return Files.newInputStream(path);
} else { // 相对路径
return FileUtil.class.getClassLoader().getResourceAsStream(fileName);
}
}
public static InputStream getStreamByFileName(String fileName) throws IOException { if (fileName == null) { throw new IllegalArgumentException("fileName should not be null!");
} if (fileName.startsWith("http")) { // 网络地址
URL url = new URL(fileName); return url.openStream();
} else if (fileName.startsWith("/")) { // 绝对路径
Path path = Paths.get(fileName); return Files.newInputStream(path);
} else { // 相对路径
return FileUtil.class.getClassLoader().getResourceAsStream(fileName);
}
}

测试用例, 测试之前在相应的地方准备好图片

@Testpublic void testReadFile() {   try {       // 绝对路径读取
String img = "/tmp/img.jpg";
BufferedImage bf1 = ImageIO.read(FileUtil.getStreamByFileName(img));
logger.info("read success!");
} catch (IOException e) {
logger.error("read absolute img error!");
} try { // 相对路径
String img2 = "avatar.jpg";
BufferedImage bf2 = ImageIO.read(FileUtil.getStreamByFileName(img2));
logger.info("read success!");
} catch (Exception e) {
logger.error("read relative img error!");
} try {
String img3 = "http://fanyi.baidu.com/static/translation/img/header/logo_cbfea26.png";
URL url = new URL(img3);
BufferedImage bf3 = ImageIO.read(FileUtil.getStreamByFileName(img3));
logger.info("read success!");
} catch (Exception e) {
logger.error("read net img error!");
}

}
@Testpublic void testReadFile() { try { // 绝对路径读取
String img = "/tmp/img.jpg";
BufferedImage bf1 = ImageIO.read(FileUtil.getStreamByFileName(img));
logger.info("read success!");
} catch (IOException e) {
logger.error("read absolute img error!");
} try { // 相对路径
String img2 = "avatar.jpg";
BufferedImage bf2 = ImageIO.read(FileUtil.getStreamByFileName(img2));
logger.info("read success!");
} catch (Exception e) {
logger.error("read relative img error!");
} try {
String img3 = "http://fanyi.baidu.com/static/translation/img/header/logo_cbfea26.png";
URL url = new URL(img3);
BufferedImage bf3 = ImageIO.read(FileUtil.getStreamByFileName(img3));
logger.info("read success!");
} catch (Exception e) {
logger.error("read net img error!");
}

}

3. 格式化文件读取

json文件读写

在 JS 语言中,一切都是对象。因此,任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型:

  • 对象表示为键值对
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组

随便写了个json串,基本上包含了json中用到的各种数据格式

{  "user": {    "name": [      "yihui",      "一灰"
], "info": { "sex": "男", "age": 26
}
}, "address": { "phone": null, "qq": true, "email": {}
}
}
{ "user": { "name": [ "yihui", "一灰"
], "info": { "sex": "男", "age": 26
}
}, "address": { "phone": null, "qq": true, "email": {}
}
}

现在有较多的json辅助工具,实现对象和JSON字符串的互转,这里我们选择fastjson作为测试用例

依赖

<!--json--><dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version></dependency>
<!--json--><dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.29</version></dependency>

工具类

/** * 读取json文件, 并转为特定对象 * @param filename * @param typeReference * @param <T> * @return* @throws IOException */public static <T> T read(String filename, TypeReference<T> typeReference) throws IOException {
BufferedReader bf = FileUtil.createLineRead(filename); try {
StringBuilder stringBuffer = new StringBuilder();
String line; while ((line = bf.readLine()) != null) {
stringBuffer.append(line);
} return JSON.parseObject(stringBuffer.toString(), typeReference);
} finally {
bf.close();
}
}
/** * 读取json文件, 并转为特定对象 * @param filename * @param typeReference * @param <T> * @return* @throws IOException */public static <T> T read(String filename, TypeReference<T> typeReference) throws IOException {
BufferedReader bf = FileUtil.createLineRead(filename); try {
StringBuilder stringBuffer = new StringBuilder();
String line; while ((line = bf.readLine()) != null) {
stringBuffer.append(line);
} return JSON.parseObject(stringBuffer.toString(), typeReference);
} finally {
bf.close();
}
}

测试用例

@Getter@Setter@ToStringprivate static class JsonDO {   private User user;   private Address address;   @Getter
@Setter
@ToString
static class User { private List<String> name; private Info info;
} @Getter
@Setter
@ToString
static class Info { private Integer age; private String sex;
} @Getter
@Setter
@ToString
static class Address { private Long phone; private Boolean qq; private Map<String, String> email;
}
}@Testpublic void testJsonRead() throws IOException {
String fileName = "info.json";

TypeReference<JsonDO> typeReference = new TypeReference<JsonDO>() {};

JsonDO jsonDO = JsonUtil.read(fileName, typeReference);
logger.info("the csv words: {}", jsonDO);
}
@Getter@Setter@ToStringprivate static class JsonDO { private User user; private Address address; @Getter
@Setter
@ToString
static class User { private List<String> name; private Info info;
} @Getter
@Setter
@ToString
static class Info { private Integer age; private String sex;
} @Getter
@Setter
@ToString
static class Address { private Long phone; private Boolean qq; private Map<String, String> email;
}
}@Testpublic void testJsonRead() throws IOException {
String fileName = "info.json";

TypeReference<JsonDO> typeReference = new TypeReference<JsonDO>() {};

JsonDO jsonDO = JsonUtil.read(fileName, typeReference);
logger.info("the csv words: {}", jsonDO);
}

输出结果

java之的读取文件大全_文件读写

xml文件读写

xml文件读写,更常见的使用场景是按照自己的意愿去选择的获取某些节点的值, 没想到什么好的方法来返回这种xml文件的数据对象,这里就给一个简单的使用测试case

主要利用 dom4j 来读写xml文件, 首先添加pom依赖

<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version></dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version></dependency>

测试case如下, 下面为待读取的 ​​demo.xml​

<?xml version="1.0" encoding="UTF-8" ?><address-list>
<card name="yangjm" id="1">
<sex>男</sex>
<address><![CDATA[中国上海外滩No.01]]> </address>
<telephone>13916732212</telephone>
</card>
<card name="zhangsan" id="2">
<sex>女</sex>
<address>
<item type="家庭地址"><![CDATA[中国.北京.东直门外大街]]> </item>
<item type="单位地址"><![CDATA[中国.上海.田林路888号]]> </item>
</address>
<telephone>010-123123</telephone>
</card></address-list>
<?xml version="1.0" encoding="UTF-8" ?><address-list>
<card name="yangjm" id="1">
<sex>男</sex>
<address><![CDATA[中国上海外滩No.01]]> </address>
<telephone>13916732212</telephone>
</card>
<card name="zhangsan" id="2">
<sex>女</sex>
<address>
<item type="家庭地址"><![CDATA[中国.北京.东直门外大街]]> </item>
<item type="单位地址"><![CDATA[中国.上海.田林路888号]]> </item>
</address>
<telephone>010-123123</telephone>
</card></address-list>

测试代码

@Test
public void test() throws IOException {
String fileName = "demo.xml";
InputStream inputStream = FileUtil.getStreamByFileName(fileName); try {
SAXReader reader = new SAXReader();
Document doc = reader.read(inputStream); //加载xml文件

List peoples = doc.selectNodes("//*[@name]"); //选择所有具有name属性的节点(即demo.xml中的所有card节点)
for (Iterator iter = peoples.iterator(); iter.hasNext(); ) {
Element card = (Element) iter.next();
List attrList = card.attributes(); //输出每个card的所有属性
for (Iterator attr = attrList.iterator(); attr.hasNext(); ) {
Attribute a = (Attribute) attr.next();
System.out.println(a.getName() + "=" + a.getValue());

}
System.out.println( "----------------------------------------------------");
}

Element zhangsan = (Element) doc.selectSingleNode("//card[@id='2']"); //查找“id属性”=2的card元素
System.out.println("张三的名称:" + zhangsan.attribute("name").getValue()); //输出zhangsan的name属性

Node addrFamily = zhangsan.selectSingleNode("./address/item[2]"); //选择zhangsan元素下的address节点下的第2个item子节点
System.out.println("张三的单位地址:" + addrFamily.getStringValue()); //输出cdata内容

System.out.println( "----------------------------------------------------"); //为zhangsan下增加二个节点
zhangsan.addElement("email").addAttribute("type", "工作").addText("work@some-domain.com");
zhangsan.addElement("email").addAttribute("type", "私人").addCDATA("private@some-domain.com"); //设置CDATA内容

System.out.println(zhangsan.asXML()); //打印zhangsan节点的xml内容(调试用)
System.out.println( "----------------------------------------------------");
} catch (Exception e) {
e.printStackTrace();
}

inputStream.close();
}
@Test
public void test() throws IOException {
String fileName = "demo.xml";
InputStream inputStream = FileUtil.getStreamByFileName(fileName); try {
SAXReader reader = new SAXReader();
Document doc = reader.read(inputStream); //加载xml文件

List peoples = doc.selectNodes("//*[@name]"); //选择所有具有name属性的节点(即demo.xml中的所有card节点)
for (Iterator iter = peoples.iterator(); iter.hasNext(); ) {
Element card = (Element) iter.next();
List attrList = card.attributes(); //输出每个card的所有属性
for (Iterator attr = attrList.iterator(); attr.hasNext(); ) {
Attribute a = (Attribute) attr.next();
System.out.println(a.getName() + "=" + a.getValue());

}
System.out.println( "----------------------------------------------------");
}

Element zhangsan = (Element) doc.selectSingleNode("//card[@id='2']"); //查找“id属性”=2的card元素
System.out.println("张三的名称:" + zhangsan.attribute("name").getValue()); //输出zhangsan的name属性

Node addrFamily = zhangsan.selectSingleNode("./address/item[2]"); //选择zhangsan元素下的address节点下的第2个item子节点
System.out.println("张三的单位地址:" + addrFamily.getStringValue()); //输出cdata内容

System.out.println( "----------------------------------------------------"); //为zhangsan下增加二个节点
zhangsan.addElement("email").addAttribute("type", "工作").addText("work@some-domain.com");
zhangsan.addElement("email").addAttribute("type", "私人").addCDATA("private@some-domain.com"); //设置CDATA内容

System.out.println(zhangsan.asXML()); //打印zhangsan节点的xml内容(调试用)
System.out.println( "----------------------------------------------------");
} catch (Exception e) {
e.printStackTrace();
}

inputStream.close();
}

yaml文件读写

多行缩进 数据结构可以用类似大纲的缩排方式呈现,结构通过缩进来表示,连续的项目通过减号“-”来表示,map结构里面的key/value对用冒号“:”来分隔 注意: 字串不一定要用双引号标识; 在缩排中空白字符的数目并不是非常重要,只要相同阶层的元素左侧对齐就可以了(不过不能使用TAB字符); 允许在文件中加入选择性的空行,以增加可读性; 在一个档案中,可同时包含多个文件,并用“——”分隔; 选择性的符号“...”可以用来表示档案结尾(在利用串流的通讯中,这非常有用,可以在不关闭串流的情况下,发送结束讯号)。

这是一种以缩进表示数据结构的表现方式,详细说明可以参考百科,解析方法依然使用开源的工具​​snakeyaml​

<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.17</version></dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.17</version></dependency>

测试文件 ​​test.yaml​

house:  family:    name: Doe    parents:      - John      - Jane    children:      - Paul      - Mark      - Simone  address:    number: 34    street: Main Street    city: Nowheretown    zipcode: 12345
house: family: name: Doe parents: - John - Jane children: - Paul - Mark - Simone address: number: 34 street: Main Street city: Nowheretown zipcode: 12345

封装实现类

/** * yaml文件读取 * * @param fileName 文件名 * @param clz 格式化的对象实例 * @param <T> * @return* @throws IOException */public static <T> T read(String fileName, Class<T> clz) throws IOException {   try (InputStream inputStream = FileUtil.getStreamByFileName(fileName)) {
Yaml yaml = new Yaml(); return yaml.loadAs(inputStream, clz);
}
}
/** * yaml文件读取 * * @param fileName 文件名 * @param clz 格式化的对象实例 * @param <T> * @return* @throws IOException */public static <T> T read(String fileName, Class<T> clz) throws IOException { try (InputStream inputStream = FileUtil.getStreamByFileName(fileName)) {
Yaml yaml = new Yaml(); return yaml.loadAs(inputStream, clz);
}
}

测试case

@Getter
@Setter
@ToString
public static class Me { private Integer age; private String name; private Map<String, Object> params; private List<String> favoriteBooks; public Me() {
}
} @Test
public void testYamlRead() throws IOException {
String fileName = "test.yaml";
Me me = YamlUtil.read(fileName, Me.class);
logger.info("me: {}", me);
}
@Getter
@Setter
@ToString
public static class Me { private Integer age; private String name; private Map<String, Object> params; private List<String> favoriteBooks; public Me() {
}
} @Test
public void testYamlRead() throws IOException {
String fileName = "test.yaml";
Me me = YamlUtil.read(fileName, Me.class);
logger.info("me: {}", me);
}

输出结果如下

java之的读取文件大全_文件读写_02


ini 文件读写

NI文件由节、键、值组成。 节 [p] 参数(键=值) name=value 注解 注解使用分号表示(;)。在分号后面的文字,直到该行结尾都全部为注解。

​ini​​​文件的格式类似 ​​properties​​文件,根据这个规则进行读写也比较简单,即便自己开发一个读写工具类,貌似也不会特别 复杂,当然也完全没有必要自己造轮子, 直接找个开源工具使用即可

<!--ini--><dependency>
<groupId>org.ini4j</groupId>
<artifactId>ini4j</artifactId>
<version>0.5.2</version></dependency>
<!--ini--><dependency>
<groupId>org.ini4j</groupId>
<artifactId>ini4j</artifactId>
<version>0.5.2</version></dependency>

测试文件 ​​test.ini​

[system]program_name=ini4jExampleversion=1.0[person_1]name=kanpiaoxue_1age=30sex=1[person_2]name=kanpiaoxue_2age=31sex=1[company]name=company1address=beijing[company]name=company1address=beijing
[system]program_name=ini4jExampleversion=1.0[person_1]name=kanpiaoxue_1age=30sex=1[person_2]name=kanpiaoxue_2age=31sex=1[company]name=company1address=beijing[company]name=company1address=beijing

封装代码

/**     * ini文件读取     * @param fileName 文件名     * @return     * @throws IOException     */
public static Ini read(String fileName) throws IOException {
InputStream inputStream = FileUtil.getStreamByFileName(fileName); try {
Config cfg = new Config(); // 设置Section允许出现重复
cfg.setMultiSection(true);
Ini ini = new Ini();
ini.setConfig(cfg);

ini.load(inputStream); return ini;

} finally {
inputStream.close();
}

}
/** * ini文件读取 * @param fileName 文件名 * @return * @throws IOException */
public static Ini read(String fileName) throws IOException {
InputStream inputStream = FileUtil.getStreamByFileName(fileName); try {
Config cfg = new Config(); // 设置Section允许出现重复
cfg.setMultiSection(true);
Ini ini = new Ini();
ini.setConfig(cfg);

ini.load(inputStream); return ini;

} finally {
inputStream.close();
}

}

测试用例

@Test
public void testIniUtilRead() throws IOException {

String fileName = "test.ini";


Ini ini = IniUtil.read(fileName);
Profile.Section p = ini.get("system");
logger.info("p: {}", p);
}
@Test
public void testIniUtilRead() throws IOException {

String fileName = "test.ini";


Ini ini = IniUtil.read(fileName);
Profile.Section p = ini.get("system");
logger.info("p: {}", p);
}

输出结果如下

java之的读取文件大全_文件读写_03



properties文件读写

properties 文件,通常用做配置文件来使用,在spring的工程中有较广泛的应用。定义也比较简单,每一行由 ​​propertyName = propertyValue​​ 这种格式组成, 其中等号前面的为name, 等号后面的value值; # 号后面为注释 properties文件更适用于kv格式的配置项

一个简单的测试case, 下面记录的是数据库的链接信息

driver=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/wolf?useUnicode=true&characterEncoding=UTF-8username=rootpassword=
driver=com.mysql.jdbc.Driverurl=jdbc:mysql://127.0.0.1:3306/wolf?useUnicode=true&characterEncoding=UTF-8username=rootpassword=

这个读取比较简单, 可以直接使用jdk的 ​​Properties​​​ 类来做, 这个类继承自 ​​Hashtable​​, 简单的封装代码如下

/** * 读取properties文件的内容 * * @param fileName 文件名 * @return* @throws IOException */public static Properties read(String fileName) throws IOException {
InputStream inputStream = FileUtil.getStreamByFileName(fileName); try {
Properties pro = new Properties();
pro.load(inputStream); return pro;
} finally {
inputStream.close();
}
}
/** * 读取properties文件的内容 * * @param fileName 文件名 * @return* @throws IOException */public static Properties read(String fileName) throws IOException {
InputStream inputStream = FileUtil.getStreamByFileName(fileName); try {
Properties pro = new Properties();
pro.load(inputStream); return pro;
} finally {
inputStream.close();
}
}

测试用例

@Testpublic void testReadProperties() throws IOException {
String fileName = "jdbc.properties";
Properties properties = PropertiesUtil.read(fileName);
logger.info("properties: {}", properties);
}
@Testpublic void testReadProperties() throws IOException {
String fileName = "jdbc.properties";
Properties properties = PropertiesUtil.read(fileName);
logger.info("properties: {}", properties);
}

输出结果如下

java之的读取文件大全_读取文件_04



csv文件读写

逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)

一个简单的实例, 一个存储词典的csv文件,共有2列,第一列为单词的id, 第二列为单词内; 第一行表示的头

dicId,"name"1,"质量"2,"服务"3,"发货"4,"性价比"5,"尺码"
dicId,"name"1,"质量"2,"服务"3,"发货"4,"性价比"5,"尺码"

对于csv文件的读取, 主要借用 apache的开源工具

<!--csv 文件读写--><dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.3</version></dependency>
<!--csv 文件读写--><dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.3</version></dependency>

简单的封装类如下, 需要注意的是返回值是一个 ​​CSVRecord​​ 对象, 需要对其进行转换; 第一列返回的是头, 需要过滤掉

/** * 读取csv文件, 返回结构话的对象 * @param filename csv 路径 + 文件名, 支持绝对路径 + 相对路径 + 网络文件 * @param headers  csv 每列的数据 * @return* @throws IOException */public static List<CSVRecord> read(String filename, String[] headers) throws IOException {
Reader reader = FileUtil.createCharRead(filename); try {
CSVParser csvParser = new CSVParser(reader,
CSVFormat.INFORMIX_UNLOAD_CSV.withHeader(headers)
); return csvParser.getRecords();
} finally {
reader.close();
}
}
/** * 读取csv文件, 返回结构话的对象 * @param filename csv 路径 + 文件名, 支持绝对路径 + 相对路径 + 网络文件 * @param headers csv 每列的数据 * @return* @throws IOException */public static List<CSVRecord> read(String filename, String[] headers) throws IOException {
Reader reader = FileUtil.createCharRead(filename); try {
CSVParser csvParser = new CSVParser(reader,
CSVFormat.INFORMIX_UNLOAD_CSV.withHeader(headers)
); return csvParser.getRecords();
} finally {
reader.close();
}
}

测试用例如下

@Getter
@Setter
@ToString
private static class WordDO {
Integer dicId;

String name;
} @Test
public void testCsvRead() throws IOException {
String fileName = "word.csv";
List<CSVRecord> list = CsvUtil.read(fileName, new String[]{"dicId", "name"});
Assert.assertTrue(list != null && list.size() > 0);

List<WordDO> words = list.stream()
.filter(csvRecord -> !"dicId".equals(csvRecord.get("dicId")))
.map(this::parseDO).collect(Collectors.toList());
logger.info("the csv words: {}", words);
} private WordDO parseDO(CSVRecord csvRecord) {
WordDO wordDO = new WordDO();
wordDO.dicId = Integer.parseInt(csvRecord.get("dicId"));
wordDO.name = csvRecord.get("name"); return wordDO;
}
@Getter
@Setter
@ToString
private static class WordDO {
Integer dicId;

String name;
} @Test
public void testCsvRead() throws IOException {
String fileName = "word.csv";
List<CSVRecord> list = CsvUtil.read(fileName, new String[]{"dicId", "name"});
Assert.assertTrue(list != null && list.size() > 0);

List<WordDO> words = list.stream()
.filter(csvRecord -> !"dicId".equals(csvRecord.get("dicId")))
.map(this::parseDO).collect(Collectors.toList());
logger.info("the csv words: {}", words);
} private WordDO parseDO(CSVRecord csvRecord) {
WordDO wordDO = new WordDO();
wordDO.dicId = Integer.parseInt(csvRecord.get("dicId"));
wordDO.name = csvRecord.get("name"); return wordDO;
}

输出结果如下

java之的读取文件大全_字符流_05


4. 源码