文章目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.util.Arrays;
import java.util.List;

/**
* @author junfeng
*/
public class CsvLine {
private final String[] items;

CsvLine(List<String> items){
if(items==null){
this.items = new String[0];
}else{
this.items = items.toArray(new String[0]);
}
}
public int length(){
return items.length;
}

/**
* 根据下标获取值,从0开始
* @param off 下标
* @return 下标对应的文本
*/
public String get(int off){
if(off<0){
throw new IllegalArgumentException("off should >= 0");
}
if(off>=this.items.length){
return null;
}
return this.items[off];
}

/**
* 获取所有项的内容列表
* @return 所有项的内容列表
*/
public List<String> getItemList(){
return Arrays.asList(this.items);
}

@Override
public String toString(){
return "[" + String.join(",",items) + "]";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
* CSV内容读取类封装
* 格式约定:
* 列分隔符:默认是逗号”,“
* 封闭符:指定源文件中使用的结束字符,默认为双引号。其中包括:双引号、单引号。
*
* 1)每条记录占一行;
* 2)分隔符 前后的空格会被忽略;
* 3)字段中包含有 分隔符,该字段必须用 封闭符 括起来;
* 4)字段中包含有换行符,该字段必须用 封闭符 括起来;
* 5)字段前后包含有空格,该字段必须用 封闭符 括起来;
* 6)字段中的 封闭符 用两个 封闭符 表示;
* 7)第一条记录,可以是字段名;
*
* 分隔符 和 封闭符 是单一字符。
* @author junfeng
*/
public class CsvReader implements Closeable {
char splitChar = ',';
char limitChar = '"';
BufferedReader br;
File file;
Charset charset = StandardCharsets.UTF_8;

/**
* CSV解析类构造函数
* @param file 要读取的文件
*/
public CsvReader(File file){
this.file = file;
}

/**
* CSV解析类构造函数
* @param file 要读取的文件
* @param charset 文件编码
*/
public CsvReader(File file,Charset charset){
this.file = file;
this.charset = charset;
}

/**
* CSV解析类构造函数
* @param file 要读取的文件
* @param charset 文件编码
* @param splitChar 分隔符
* @param limitChar 限定符
*/
public CsvReader(File file,Charset charset,char splitChar,char limitChar){
this.file = file;
this.charset = charset;
this.splitChar = splitChar;
this.limitChar = limitChar;
}

/**
* 读取一行 CSV 内容,正常返回 CsvLine 对象,读到文件结束,则返回null
* @return CsvLine 封装的内容
* @throws IOException 文件读取异常
*/
public CsvLine readLine() throws IOException{
if(br==null){
br = new BufferedReader(new InputStreamReader(new FileInputStream(this.file),charset));
}
// 标记当前是否位于 限定符内
boolean inLimit = false;
List<String> list = new ArrayList<>();
StringBuilder sbItem = new StringBuilder();
// 标记当前项是否由限定符 包括,如果包括 加入项列表时 不会清空前后的空格
boolean itemInLimit = false;
int nextChar = -1;
while (true){
int c = nextChar;
nextChar = -1;
if(c==-1){
c = br.read();
}
if(inLimit){
if(c==limitChar){
nextChar = br.read();
if(nextChar==limitChar){
sbItem.append((char)c);
nextChar = -1;
}else{
inLimit = false;
}
}else{
sbItem.append((char)c);
}
}else{
if(c==limitChar){
inLimit = true;
sbItem = new StringBuilder();
itemInLimit = true;
}else if(c==splitChar){
if(itemInLimit){
list.add(sbItem.toString());
}else{
list.add(sbItem.toString().trim());
}
itemInLimit = false;
sbItem = new StringBuilder();
}else if(c=='\r'){
// 啥也不干
}else if(c=='\n'){
if(sbItem.length()>0){
if(itemInLimit){
list.add(sbItem.toString());
}else{
list.add(sbItem.toString().trim());
}
}
break;
}else{
sbItem.append((char)c);
}
}

if(c==-1){
if(list.size()==0){
return null;
}
break;
}
}
return new CsvLine(list);
}

@Override
public void close() throws IOException {
if(br!=null){
br.close();
}
}

public static void main(String[] args) throws IOException {
CsvReader reader = new CsvReader(new File("c:/tmp/31.csv"),Charset.forName("gbk"));
CsvLine line;
while ((line=reader.readLine())!=null){
System.out.println(line);
}
}
}
文章目录