Skip to content

Commit 2eb988b

Browse files
Merge pull request #742 from ie3-institute/ms/#723-use-nio-paths-instead-of-strings
Use nio paths instead of strings
2 parents 275fb46 + 04463a9 commit 2eb988b

34 files changed

+747
-651
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
src/test/resources/edu/ie3/datamodel/io/source/influxdb/_weather/cosmo/weather.txt eol=lf
44
src/test/resources/edu/ie3/datamodel/io/source/influxdb/_weather/icon/weather.txt eol=lf
55

6+
gradlew eol=lf

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
- Removing deprecated classes and methods [#540](https://github.com/ie3-institute/PowerSystemDataModel/issues/540)
2020
- Refactor CSV data sources [#716](https://github.com/ie3-institute/PowerSystemDataModel/issues/716)
2121
- Deleted parameter initFiles, set parameter append to false by default [#791](https://github.com/ie3-institute/PowerSystemDataModel/issues/791)
22+
- Use nio paths instead of strings for file path [#723](https://github.com/ie3-institute/PowerSystemDataModel/issues/723)
2223

2324

2425
## [3.0.0] - 2023-02-16

src/main/java/edu/ie3/datamodel/io/IoUtil.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
package edu.ie3.datamodel.io;
77

88
import java.io.File;
9+
import java.nio.file.Path;
10+
import java.util.Optional;
911

1012
public class IoUtil {
1113
public static final String FILE_SEPARATOR_REGEX = "[\\\\/]";
@@ -17,13 +19,34 @@ private IoUtil() {
1719
}
1820

1921
/**
20-
* Ensure to have harmonized file separator across the whole String. Will replace all occurences
21-
* if "\" and "/" by the systems file separator
22+
* Ensure to have harmonized file separator across the whole String. Will replace all occurrences
23+
* of "\" and "/" by the systems file separator.
2224
*
2325
* @param in The String to harmonize
2426
* @return The harmonized String
2527
*/
2628
public static String harmonizeFileSeparator(String in) {
2729
return in.replaceAll(FILE_SEPARATOR_REGEX, FILE_SEPARATOR_REPLACEMENT);
2830
}
31+
32+
/**
33+
* Ensure to have harmonized file separator across the whole path. Will replace all occurrences *
34+
* of "\" and "/" by the systems file separator.
35+
*
36+
* @param path the path to harmonize
37+
* @return the harmonized path
38+
*/
39+
public static Path harmonizeFileSeparator(Path path) {
40+
return Path.of(IoUtil.harmonizeFileSeparator(path.toString()));
41+
}
42+
43+
/**
44+
* Method to wrap a string of a path in an option for a path.
45+
*
46+
* @param in string of the path
47+
* @return option of the path
48+
*/
49+
public static Optional<Path> pathOption(String in) {
50+
return Optional.of(Path.of(in));
51+
}
2952
}

src/main/java/edu/ie3/datamodel/io/connectors/CsvFileConnector.java

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@
2020
import java.nio.charset.StandardCharsets;
2121
import java.nio.file.Files;
2222
import java.nio.file.Path;
23-
import java.nio.file.Paths;
2423
import java.util.*;
2524
import java.util.function.Function;
2625
import java.util.stream.Collectors;
2726
import java.util.stream.Stream;
28-
import org.apache.commons.io.FilenameUtils;
2927
import org.slf4j.Logger;
3028
import org.slf4j.LoggerFactory;
3129

@@ -44,11 +42,11 @@ public class CsvFileConnector implements DataConnector {
4442
private final Map<UUID, BufferedCsvWriter> timeSeriesWriters = new HashMap<>();
4543

4644
private final FileNamingStrategy fileNamingStrategy;
47-
private final String baseDirectoryName;
45+
private final Path baseDirectoryName;
4846

4947
private static final String FILE_ENDING = ".csv";
5048

51-
public CsvFileConnector(String baseDirectoryName, FileNamingStrategy fileNamingStrategy) {
49+
public CsvFileConnector(Path baseDirectoryName, FileNamingStrategy fileNamingStrategy) {
5250
this.baseDirectoryName = baseDirectoryName;
5351
this.fileNamingStrategy = fileNamingStrategy;
5452
}
@@ -102,16 +100,15 @@ BufferedCsvWriter getOrInitWriter(T timeSeries, String[] headerElements, String
102100
* @throws ConnectorException If the base folder is a file
103101
* @throws IOException If the writer cannot be initialized correctly
104102
*/
105-
private BufferedCsvWriter initWriter(String baseDirectory, CsvFileDefinition fileDefinition)
103+
private BufferedCsvWriter initWriter(Path baseDirectory, CsvFileDefinition fileDefinition)
106104
throws ConnectorException, IOException {
107105
/* Join the full DIRECTORY path (excluding file name) */
108-
String baseDirectoryHarmonized = IoUtil.harmonizeFileSeparator(baseDirectory);
109-
String fullDirectoryPath =
110-
FilenameUtils.concat(baseDirectoryHarmonized, fileDefinition.directoryPath());
111-
String fullPath = FilenameUtils.concat(baseDirectoryHarmonized, fileDefinition.getFilePath());
106+
Path baseDirectoryHarmonized = IoUtil.harmonizeFileSeparator(baseDirectory);
107+
Path fullDirectoryPath = baseDirectoryHarmonized.resolve(fileDefinition.getDirectoryPath());
108+
Path fullPath = baseDirectoryHarmonized.resolve(fileDefinition.getFilePath());
112109

113110
/* Create missing directories */
114-
File directories = new File(fullDirectoryPath);
111+
File directories = fullDirectoryPath.toFile();
115112
if (directories.isFile())
116113
throw new ConnectorException("Directory '" + directories + "' already exists and is a file!");
117114
if (!directories.exists() && !directories.mkdirs())
@@ -169,10 +166,10 @@ public synchronized <C extends UniqueEntity> void closeEntityWriter(Class<C> clz
169166
* @return the reader that contains information about the file to be read in
170167
* @throws FileNotFoundException If the matching file cannot be found
171168
*/
172-
public BufferedReader initReader(Class<? extends UniqueEntity> clz) throws FileNotFoundException {
173-
String filePath = null;
169+
public BufferedReader initReader(Class<? extends UniqueEntity> clz)
170+
throws FileNotFoundException, ConnectorException {
174171
try {
175-
filePath =
172+
Path filePath =
176173
fileNamingStrategy
177174
.getFilePath(clz)
178175
.orElseThrow(
@@ -181,13 +178,11 @@ public BufferedReader initReader(Class<? extends UniqueEntity> clz) throws FileN
181178
"Cannot find a naming strategy for class '"
182179
+ clz.getSimpleName()
183180
+ "'."));
181+
return initReader(filePath);
184182
} catch (ConnectorException e) {
185-
log.error(
186-
"Cannot get reader for entity '{}' as no file naming strategy for this file exists. Exception: {}",
187-
clz.getSimpleName(),
188-
e);
183+
throw new ConnectorException(
184+
"Cannot initialize reader for entity '" + clz.getSimpleName() + "'.", e);
189185
}
190-
return initReader(filePath);
191186
}
192187

193188
/**
@@ -198,8 +193,8 @@ public BufferedReader initReader(Class<? extends UniqueEntity> clz) throws FileN
198193
* @return the reader that contains information about the file to be read in
199194
* @throws FileNotFoundException if no file with the provided file name can be found
200195
*/
201-
public BufferedReader initReader(String filePath) throws FileNotFoundException {
202-
File fullPath = new File(baseDirectoryName + File.separator + filePath + FILE_ENDING);
196+
public BufferedReader initReader(Path filePath) throws FileNotFoundException {
197+
File fullPath = baseDirectoryName.resolve(filePath.toString() + FILE_ENDING).toFile();
203198
return new BufferedReader(
204199
new InputStreamReader(new FileInputStream(fullPath), StandardCharsets.UTF_8), 16384);
205200
}
@@ -219,9 +214,9 @@ public BufferedReader initReader(String filePath) throws FileNotFoundException {
219214
filePath -> {
220215
/* Extract meta information from file path and enhance it with the file path itself */
221216
IndividualTimeSeriesMetaInformation metaInformation =
222-
fileNamingStrategy.individualTimeSeriesMetaInformation(filePath);
217+
fileNamingStrategy.individualTimeSeriesMetaInformation(filePath.toString());
223218
return new CsvIndividualTimeSeriesMetaInformation(
224-
metaInformation, FileNamingStrategy.removeFileNameEnding(filePath));
219+
metaInformation, FileNamingStrategy.removeFileNameEnding(filePath.getFileName()));
225220
})
226221
.filter(
227222
metaInformation ->
@@ -238,23 +233,20 @@ public BufferedReader initReader(String filePath) throws FileNotFoundException {
238233
*
239234
* @return A set of relative paths to time series files, with respect to the base folder path
240235
*/
241-
private Set<String> getIndividualTimeSeriesFilePaths() {
242-
Path baseDirectoryPath =
243-
Paths.get(
244-
FilenameUtils.getFullPath(baseDirectoryName)
245-
+ FilenameUtils.getName(baseDirectoryName));
236+
private Set<Path> getIndividualTimeSeriesFilePaths() {
237+
Path baseDirectoryPath = baseDirectoryName.resolve(baseDirectoryName);
246238
try (Stream<Path> pathStream = Files.walk(baseDirectoryPath)) {
247239
return pathStream
248240
.map(baseDirectoryPath::relativize)
249241
.filter(
250242
path -> {
251-
String withoutEnding = FileNamingStrategy.removeFileNameEnding(path.toString());
243+
Path withoutEnding =
244+
Path.of(FileNamingStrategy.removeFileNameEnding(path.toString()));
252245
return fileNamingStrategy
253246
.getIndividualTimeSeriesPattern()
254-
.matcher(withoutEnding)
247+
.matcher(withoutEnding.toString())
255248
.matches();
256249
})
257-
.map(Path::toString)
258250
.collect(Collectors.toSet());
259251
} catch (IOException e) {
260252
log.error("Unable to determine time series files readers for time series.", e);
@@ -270,7 +262,7 @@ private Set<String> getIndividualTimeSeriesFilePaths() {
270262
* @throws FileNotFoundException If the file is not present
271263
*/
272264
public BufferedReader initIdCoordinateReader() throws FileNotFoundException {
273-
String filePath = fileNamingStrategy.getIdCoordinateEntityName();
265+
Path filePath = Path.of(fileNamingStrategy.getIdCoordinateEntityName());
274266
return initReader(filePath);
275267
}
276268

@@ -286,7 +278,7 @@ public BufferedReader initIdCoordinateReader() throws FileNotFoundException {
286278
private <T extends TimeSeries<E, V>, E extends TimeSeriesEntry<V>, V extends Value>
287279
CsvFileDefinition buildFileDefinition(T timeSeries, String[] headLineElements, String csvSep)
288280
throws ConnectorException {
289-
String directoryPath = fileNamingStrategy.getDirectoryPath(timeSeries).orElse("");
281+
Path directoryPath = fileNamingStrategy.getDirectoryPath(timeSeries).orElse(Path.of(""));
290282
String fileName =
291283
fileNamingStrategy
292284
.getEntityName(timeSeries)
@@ -309,7 +301,7 @@ CsvFileDefinition buildFileDefinition(T timeSeries, String[] headLineElements, S
309301
private CsvFileDefinition buildFileDefinition(
310302
Class<? extends UniqueEntity> clz, String[] headLineElements, String csvSep)
311303
throws ConnectorException {
312-
String directoryPath = fileNamingStrategy.getDirectoryPath(clz).orElse("");
304+
Path directoryPath = fileNamingStrategy.getDirectoryPath(clz).orElse(Path.of(""));
313305
String fileName =
314306
fileNamingStrategy
315307
.getEntityName(clz)

src/main/java/edu/ie3/datamodel/io/csv/BufferedCsvWriter.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import edu.ie3.util.StringUtils;
1010
import java.io.*;
1111
import java.nio.charset.StandardCharsets;
12+
import java.nio.file.Path;
1213
import java.util.Arrays;
1314
import java.util.Map;
1415
import java.util.Objects;
@@ -39,10 +40,11 @@ public class BufferedCsvWriter extends BufferedWriter {
3940
* if no file exists, a new one will be created in both cases
4041
* @throws IOException If the FileOutputStream cannot be established.
4142
*/
42-
public BufferedCsvWriter(
43-
String filePath, String[] headLineElements, String csvSep, boolean append)
43+
public BufferedCsvWriter(Path filePath, String[] headLineElements, String csvSep, boolean append)
4444
throws IOException {
45-
super(new OutputStreamWriter(new FileOutputStream(filePath, append), StandardCharsets.UTF_8));
45+
super(
46+
new OutputStreamWriter(
47+
new FileOutputStream(filePath.toFile(), append), StandardCharsets.UTF_8));
4648
this.headLineElements = headLineElements;
4749
this.csvSep = csvSep;
4850
}
@@ -59,10 +61,10 @@ public BufferedCsvWriter(
5961
* if no file exists, a new one will be created in both cases
6062
* @throws IOException If the FileOutputStream cannot be established.
6163
*/
62-
public BufferedCsvWriter(String baseFolder, CsvFileDefinition fileDefinition, boolean append)
64+
public BufferedCsvWriter(Path baseFolder, CsvFileDefinition fileDefinition, boolean append)
6365
throws IOException {
6466
this(
65-
baseFolder + File.separator + fileDefinition.getFilePath(),
67+
baseFolder.resolve(fileDefinition.getFilePath()),
6668
fileDefinition.headLineElements(),
6769
fileDefinition.csvSep(),
6870
append);

src/main/java/edu/ie3/datamodel/io/csv/CsvFileDefinition.java

Lines changed: 24 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,63 +5,36 @@
55
*/
66
package edu.ie3.datamodel.io.csv;
77

8-
import edu.ie3.datamodel.io.IoUtil;
8+
import edu.ie3.datamodel.utils.FileUtils;
9+
import java.nio.file.Path;
910
import java.util.Arrays;
1011
import java.util.Objects;
11-
import java.util.regex.Matcher;
12-
import java.util.regex.Pattern;
13-
import org.apache.commons.io.FilenameUtils;
14-
import org.slf4j.Logger;
15-
import org.slf4j.LoggerFactory;
16-
17-
public record CsvFileDefinition(
18-
String fileName, String directoryPath, String[] headLineElements, String csvSep) {
19-
private static final Logger logger = LoggerFactory.getLogger(CsvFileDefinition.class);
20-
21-
private static final Pattern FILE_NAME_PATTERN =
22-
Pattern.compile(
23-
"^(?<fileName>[^\\\\/\\s.]{0,255})(?:\\.(?<extension>[a-zA-Z0-9]{0,10}(?:\\.[a-zA-Z0-9]{0,10})?))?$");
24-
25-
private static final String FILE_EXTENSION = "csv";
2612

13+
/**
14+
* A definition of a csv file.
15+
*
16+
* @param filePath the path of the csv file (including filename and relative path)
17+
* @param headLineElements elements of the headline of the defined file
18+
* @param csvSep the separator that is used in this csv file
19+
*/
20+
public record CsvFileDefinition(Path filePath, String[] headLineElements, String csvSep) {
2721
public CsvFileDefinition(
28-
String fileName, String directoryPath, String[] headLineElements, String csvSep) {
29-
/* Remove all file separators at the beginning and end of a directory path and ensure harmonized file separator */
30-
this.directoryPath =
31-
Objects.nonNull(directoryPath)
32-
? IoUtil.harmonizeFileSeparator(
33-
directoryPath
34-
.replaceFirst("^" + IoUtil.FILE_SEPARATOR_REGEX, "")
35-
.replaceAll(IoUtil.FILE_SEPARATOR_REGEX + "$", ""))
36-
: "";
37-
38-
/* Check the given information of the file name */
39-
Matcher matcher = FILE_NAME_PATTERN.matcher(fileName);
40-
if (matcher.matches()) {
41-
String extension = matcher.group("extension");
42-
if (Objects.nonNull(extension) && !extension.equalsIgnoreCase(FILE_EXTENSION))
43-
logger.warn(
44-
"You provided a file name with extension '{}'. It will be overridden to '{}'.",
45-
extension,
46-
FILE_EXTENSION);
47-
this.fileName = matcher.group("fileName") + "." + FILE_EXTENSION;
48-
} else {
49-
throw new IllegalArgumentException(
50-
"The file name '"
51-
+ fileName
52-
+ "' is no valid file name. It may contain everything, except '/', '\\', '.' and any white space character.");
53-
}
54-
55-
this.headLineElements = headLineElements;
56-
this.csvSep = csvSep;
22+
String fileName, Path directoryPath, String[] headLineElements, String csvSep) {
23+
this(FileUtils.ofCsv(fileName, directoryPath), headLineElements, csvSep);
5724
}
5825

5926
/**
6027
* @return The path to the file relative to a not explicitly defined base directory, including the
6128
* file extension
6229
*/
63-
public String getFilePath() {
64-
return !directoryPath.isEmpty() ? FilenameUtils.concat(directoryPath, fileName) : fileName;
30+
public Path getFilePath() {
31+
return filePath;
32+
}
33+
34+
/** Returns the directory path of this file. */
35+
public Path getDirectoryPath() {
36+
Path parent = filePath.getParent();
37+
return parent != null ? parent : Path.of("");
6538
}
6639

6740
@Override
@@ -70,27 +43,23 @@ public boolean equals(Object o) {
7043
// records' equals method and array fields don't play together nicely
7144
if (this == o) return true;
7245
if (!(o instanceof CsvFileDefinition that)) return false;
73-
return directoryPath.equals(that.directoryPath)
74-
&& fileName.equals(that.fileName)
46+
return filePath.equals(that.filePath)
7547
&& Arrays.equals(headLineElements, that.headLineElements)
7648
&& csvSep.equals(that.csvSep);
7749
}
7850

7951
@Override
8052
public int hashCode() {
81-
int result = Objects.hash(directoryPath, fileName, csvSep);
53+
int result = Objects.hash(filePath, csvSep);
8254
result = 31 * result + Arrays.hashCode(headLineElements);
8355
return result;
8456
}
8557

8658
@Override
8759
public String toString() {
8860
return "CsvFileDefinition{"
89-
+ "directoryPath='"
90-
+ directoryPath
91-
+ '\''
92-
+ ", fileName='"
93-
+ fileName
61+
+ "fullPath='"
62+
+ filePath
9463
+ '\''
9564
+ ", headLineElements="
9665
+ Arrays.toString(headLineElements)

0 commit comments

Comments
 (0)