Reputation: 63
I want to read a text file which has String and a few integers related to that string.
This is the class that I have to write my program in:
public List<Integer> Data(String name) throws IOException {
return null;
}
I have to read the .txt file and find the name in that file, with its data. And save it in an ArrayList
.
My question is how do I save it in the ArrayList<Integer>
when I have String
s in the List
.
This is what I think I would do:
Scanner s = new Scanner(new File(filename));
ArrayList<Integer> data = new ArrayList<Integer>();
while (s.hasNextLine()) {
data.add(s.nextInt());
}
s.close();
Upvotes: 6
Views: 1309
Reputation: 21576
If you want to use java8 you could use something like this.
Input.txt (has to be in classpath):
text1;4711;4712
text2;42;43
The code:
public class Main {
public static void main(String[] args) throws IOException, URISyntaxException {
// find file in classpath
Path path = Paths.get(ClassLoader.getSystemResource("input.txt").toURI());
// find the matching line
findLineData(path, "text2")
// print each value as line to the console output
.forEach(System.out::println);
}
/** searches for a line in a textfile and returns the line's data */
private static IntStream findLineData(Path path, String searchText) throws IOException {
// securely open the file in a "try" block and read all lines as stream
try (Stream<String> lines = Files.lines(path)) {
return lines
// split each line by a separator pattern (semicolon in this example)
.map(line -> line.split(";"))
// find the line, whiches first element matches the search criteria
.filter(data -> searchText.equals(data[0]))
// foreach match make a stream of all of the items
.map(data -> Arrays.stream(data)
// skip the first one (the string name)
.skip(1)
// parse all values from String to int
.mapToInt(Integer::parseInt))
// return one match
.findAny().get();
}
}
}
The output:
42
43
Upvotes: 0
Reputation: 201439
I would define the file as a field (in addition to the filename
, and I suggest reading it from the user's home folder) file
private File file = new File(System.getProperty("user.home"), filename);
Then you can use the diamond operator <>
when you define your List
. You can use a try-with-resources
to close
your Scanner
. You want to read by lines. And you can split
your line
. Then you test if your first column matches the name. If it does, iterate the other columns are parse them to int
. Something like
public List<Integer> loadDataFor(String name) throws IOException {
List<Integer> data = new ArrayList<>();
try (Scanner s = new Scanner(file)) {
while (s.hasNextLine()) {
String[] row = s.nextLine().split("\\s+");
if (row[0].equalsIgnoreCase(name)) {
for (int i = 1; i < row.length; i++) {
data.add(Integer.parseInt(row[i]));
}
}
}
}
return data;
}
It might be signifanctly more efficient to scan the file once and store the names and fields as a Map<String, List<Integer>>
like
public static Map<String, List<Integer>> readFile(String filename) {
Map<String, List<Integer>> map = new HashMap<>();
File file = new File(System.getProperty("user.home"), filename);
try (Scanner s = new Scanner(file)) {
while (s.hasNextLine()) {
String[] row = s.nextLine().split("\\s+");
List<Integer> al = new ArrayList<>();
for (int i = 1; i < row.length; i++) {
al.add(Integer.parseInt(row[i]));
}
map.put(row[0], al);
}
} catch (Exception e) {
e.printStackTrace();
}
return map;
}
Then store that as fileContents
like
private Map<String, List<Integer>> fileContents = readFile(filename);
And then implement your loadDataFor(String)
method with fileContents
like
public List<Integer> loadDataFor(String name) throws IOException {
return fileContents.get(name);
}
If your usage pattern reads the File
for many names then the second is likely to be much faster.
Upvotes: 3