基于流式输入输出 使用Java借助GSON库 实现对大型asc文件的读入解析 并输出为JSON文件
致谢
参考文章
1 为什么要使用流式输入输出(使用情景)
解决 在进行非流式输入输出时,当需处理的文件 过大 时(比如上G的数据文件),无法将整个完整的文件放入内存,导致堆栈溢出,GC溢出等情况。
2 目标、主要思路及相关方法
2.1 目标
将大型asc文件的数据解析后,转换成JSON文件
2.2 思路
对读入的asc文件每次提取一部分内容,解析后,调用GSON库生成相应的一部分JSON文件并写出。
2.3 相关方法
2.3.1 读入相关
使用的主要java相关读入类
- BufferedReader
其相关方法
- bufferedReader.readLine() - - 按行读取
2.3.2 输出相关
使用的主要GSON类
- JsonWriter
其相关方法
- new JsonWriter(new FileWriter(xxx)) - - 构造方法
- writer.beginObject() - - 开始写JSON文件 相当于写JSON文件的 { 对象开始符号
- writer.endObject() - - 结束JSON文件 相当于写JSON文件的 } 对象结束符号
- writer.name(xxx) - - 写入一个键名为xxx的键
- writer.value(yyy) - - 写入一个值为yyy的值
- writer.name(xxx).value(yyy) - - 写入一个键为xxx,值为yyy的键值对
- writer.beginArray() - - 开始一个数组 相当于写JSON文件的 [ 符号
- writer.endArray() - - 结束一个数组 相当于写JSON文件的 ] 符号
- writer.close() 关闭输出器
相关方法输出解析示例
3 示例
3.1 环境
GSON库的maven依赖
<!--GSON依赖-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
3.2 测试数据
读入的asc文件
文件的类似基本结构(按行排列,不定量的空格做单个数据分隔)
读入的asc文件的结构 关系到 其相应 提取数据的策略
3.3 测试代码 - Java
main()入口方法
// 输入设置
String fileName = "zhemindem_30.asc";
String filePath = "C:\\dataTest\\asc\\";
String bigFile = filePath + fileName;
// 输出设置
String outFileParent2 = "E:\\json\\";
String outputFile2 = outFileParent2 + fileName.replaceAll(".asc", ".json");
String encoding2 = "utf-8";
// 转换方法
convertBigFile(bigFile, outputFile2, encoding2);
具体转换方法 - convertBigFile()
public static void convertBigFile(String inputFile, String outputFile, String encoding){
// 将文件名作为主体数据部分的键名
String dataKey = inputFile.substring(inputFile.lastIndexOf("\\")+1).split(".asc")[0];
File file = new File(inputFile);
FileReader fileReader = null;
BufferedReader bufferedReader = null;
JsonWriter writer;
String temp;
int count = 0;
// asc文件总行数
int nrows = 0;
// asc文件总列数
int ncols = 0;
try {
fileReader = new FileReader(file);
// 读入器
bufferedReader = new BufferedReader(fileReader);
// 写出器
writer = new JsonWriter(new FileWriter(outputFile));
//开始准备生成JSON文件
writer.beginObject(); // {
while((temp = bufferedReader.readLine())!=null){
System.err.println("currentRow: " + count);
// 解析当前行,前6行 为属性,后面行 为数据
String[] result = temp.split(" +");
if (count == 0 ) {
System.out.println(count + " : " + temp);
// result[0]属性名,result[1]属性值
ncols = Integer.parseInt(result[1]);
writer.name(result[0]).value(ncols);
}else if(count == 1){
System.out.println(count + " : " + temp);
nrows = Integer.parseInt(result[1]);
writer.name(result[0]).value(nrows);
}else if(count < 5){
System.out.println(count + " : " + temp);
writer.name(result[0]).value(Double.parseDouble(result[1]));
}else if(count == 5){
System.out.println(count + " : " + temp);
writer.name(result[0]).value(Integer.parseInt(result[1]));
//开始准备写入数据
writer.name(dataKey);
writer.beginArray(); // [
}else if(count < nrows){
writer.beginArray(); // [
for(String eachCol: result){
writer.value(Short.parseShort(eachCol));
}
writer.endArray(); // ]
}else if(count == nrows){
writer.endArray(); // ]
//结束JSON文件
writer.endObject(); // }
writer.close();
System.out.println("写出器退出!");
}
else{
break;
}
count++;
}
fileReader.close();
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
try{
if (bufferedReader != null) {
bufferedReader.close();
}
if(fileReader != null){
fileReader.close();
}
System.out.println("读取文件成功!");
}catch (IOException e) {
System.out.println("读取文件失败!");
e.printStackTrace();
}
}
}
3.4 测试结果
3.5 注意事项
① 对自定义的读入文件的按行读取,读取解析时需要根据读入文件的特点进行设计。(示例为zhemindem_30.asc文件)
② 需要小心、准确使用如下方法
writer.beginArray();
writer.endArray();
若出现不恰当的使用,导致多出 [ 符号或者 ] 符号,将出现 nest 异常,使程序退出。