-
Notifications
You must be signed in to change notification settings - Fork 5
/
BufferedCsvWriter.java
163 lines (146 loc) · 5.41 KB
/
BufferedCsvWriter.java
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
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
* © 2021. TU Dortmund University,
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
* Research group Distribution grid planning and operation
*/
package edu.ie3.datamodel.io.csv;
import edu.ie3.datamodel.exceptions.SinkException;
import edu.ie3.util.StringUtils;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* This class extends the {@link BufferedWriter} and adds information about the file shape of the
* csv file
*/
public class BufferedCsvWriter extends BufferedWriter {
/** Information on the shape of the file */
private final String[] headLineElements;
private final String csvSep;
private static final String APPENDING_WARNING =
"Direct appending is prohibited. Use write instead.";
/**
* Build a new CsvBufferedWriter. The order of headline elements given in this constructor defines
* the order of columns in file
*
* @param filePath String representation of the full path to the target file
* @param headLineElements Elements of the csv headline
* @param csvSep csv separator char
* @param append true to append to an existing file, false to overwrite an existing file (if any),
* if no file exists, a new one will be created in both cases
* @throws IOException If the FileOutputStream cannot be established.
*/
public BufferedCsvWriter(Path filePath, String[] headLineElements, String csvSep, boolean append)
throws IOException {
super(
new OutputStreamWriter(
new FileOutputStream(filePath.toFile(), append), StandardCharsets.UTF_8));
this.headLineElements = headLineElements;
this.csvSep = csvSep;
}
/**
* Build a new CsvBufferedWriter. This is a "convenience" Constructor. The absolute file path is
* assembled by concatenation of {@code baseFolder} and {@code fileDefinition}'s file path
* information. The order of headline elements in {@code fileDefinition} defines the order of
* columns in file
*
* @param baseFolder Base folder, from where the file hierarchy should start
* @param fileDefinition The foreseen shape of the file
* @param append true to append to an existing file, false to overwrite an existing file (if any),
* if no file exists, a new one will be created in both cases
* @throws IOException If the FileOutputStream cannot be established.
*/
public BufferedCsvWriter(Path baseFolder, CsvFileDefinition fileDefinition, boolean append)
throws IOException {
this(
baseFolder.resolve(fileDefinition.getFilePath()),
fileDefinition.headLineElements(),
fileDefinition.csvSep(),
append);
}
/**
* Actually persisting the provided entity field data
*
* @param entityFieldData a mapping of an entity instance fields to their values
* @throws IOException If writing has failed
* @throws SinkException If the data does not meet the pre-defined head line
*/
public synchronized void write(Map<String, String> entityFieldData)
throws IOException, SinkException {
/* Check against eligible headline elements */
if (entityFieldData.size() != headLineElements.length
|| !entityFieldData.keySet().containsAll(Arrays.asList(headLineElements)))
throw new SinkException(
"The provided data does not meet the pre-defined head line elements '"
+ String.join(",", headLineElements)
+ "'.");
writeOneLine(Arrays.stream(headLineElements).map(entityFieldData::get));
}
/**
* Writes the file header.
*
* @throws IOException If something is messed up
*/
public final synchronized void writeFileHeader() throws IOException {
writeOneLine(StringUtils.camelCaseToSnakeCase(headLineElements));
}
/**
* Writes one line to the csv file
*
* @param entries Entries to write to the line of the file
* @throws IOException If writing is not possible
*/
private void writeOneLine(String[] entries) throws IOException {
writeOneLine(Arrays.stream(entries));
}
/**
* Write one line to the csv file
*
* @param entries Stream of entries to write
* @throws IOException If writing is not possible
*/
private void writeOneLine(Stream<String> entries) throws IOException {
super.append(entries.collect(Collectors.joining(csvSep)));
super.append("\n");
flush();
}
@Override
public Writer append(CharSequence csq) {
throw new UnsupportedOperationException(APPENDING_WARNING);
}
@Override
public Writer append(CharSequence csq, int start, int end) {
throw new UnsupportedOperationException(APPENDING_WARNING);
}
@Override
public Writer append(char c) {
throw new UnsupportedOperationException(APPENDING_WARNING);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BufferedCsvWriter that)) return false;
return Arrays.equals(headLineElements, that.headLineElements) && csvSep.equals(that.csvSep);
}
@Override
public int hashCode() {
int result = Objects.hash(csvSep);
result = 31 * result + Arrays.hashCode(headLineElements);
return result;
}
@Override
public String toString() {
return "BufferedCsvWriter{"
+ "headLineElements="
+ Arrays.toString(headLineElements)
+ ", csvSep='"
+ csvSep
+ '\''
+ '}';
}
}