Max Orozco
Max Orozco

Reputation: 33

Java reading Strings from a file

I am having trouble with this method. The method is supposed to read a text file for a series of data (Attack ID [int], date [String saved in the format MM/DD/YYYY], name of monster [String], location [String], and reporter of the attack [String])separated by commas and put those values into an ArrayList called monsterAttacks. Every time I run this method I get an InputMismatchException. I have a feeling it has something to do with the date but I'm not sure where or how to use the String split() method in this case. How can I make this work properly?

Disclaimer: This is part of a homework assignment.

Thanks in advance.

Edit: Sample Data from text file:

23,12/23/1994,Dracula,California,Trisha Takinawa

25,11/12/1992,Godzilla,New York,David

private void readFromFile(){
    if(!(monsterAttacks.isEmpty())) {
        monsterAttacks.clear();
        System.out.println("\nList cleared...");
    }
    System.out.println("Enter path: ");
    String pathName = getUserInput();
    File file = new File(pathName);
    Scanner read;
    MonsterAttack attack;

    try {
        read = new Scanner(file);
        do {
            int id = read.nextInt();
            String date = read.next();
            String name = read.next();
            String location = read.next();
            String reporter = read.next();
            attack = new MonsterAttack(id, date, name, location, reporter);
            monsterAttacks.add(attack);
        } while (read.hasNext());

        read.close();
    } catch(IOException e){
        e.printStackTrace();
    }

}

Upvotes: 1

Views: 557

Answers (4)

Tim Biegeleisen
Tim Biegeleisen

Reputation: 520878

You told us that your data is

separated by commas

If so, then you would have to take these token separators into account. One way to proceed here would be to just read in an entire line and then split by comma to access each term:

try {
    read = new Scanner(file);
    do {
        String line = read.nextLine();
        String[] parts = line.split(",\\s*");
        int id = Integer.parseInt(parts[0]);
        String date = parts[1];
        String name = parts[2];
        String location = parts[3];
        String reporter = parts[4];
        attack = new MonsterAttack(id, date, name, location, reporter);
        monsterAttacks.add(attack);
    } while (read.hasNext());

    read.close();
} catch(IOException e){
    e.printStackTrace();
}

Upvotes: 1

nuvio
nuvio

Reputation: 2625

Some good answers have been provided already, I just wanted to point out a more "professional" solution in the case you were looking into a developing a structured application then consider Spring Batch flat file reader here.

Although I am not crazy i know this is quite a overhead and I understand this is a homework and possibly a simple Java application. I just think this is a nice reference for the future though.

With flat file reader / writer you can map your flat file into a POJO (Plain Old Java Object) and you can also use Spring batch to concatenate operations to give your batch application a nicer structure.

Here a simple snippet of how it works (from the link above):

@Configuration
public class CsvFileToDatabaseJobConfig {

    @Bean
    ItemReader<StudentDTO> csvFileItemReader() {
        FlatFileItemReader<StudentDTO> csvFileReader = new FlatFileItemReader<>();
        csvFileReader.setResource(new ClassPathResource("data/students.csv"));
        csvFileReader.setLinesToSkip(1);
 ...
    }

    private LineMapper<StudentDTO> createStudentLineMapper() {
        ...
    }

    private LineTokenizer createStudentLineTokenizer() {
        DelimitedLineTokenizer studentLineTokenizer = new DelimitedLineTokenizer();
        studentLineTokenizer.setDelimiter(";");
        studentLineTokenizer.setNames(new String[]{"name", "emailAddress", "purchasedPackage"});
        return studentLineTokenizer;
    }

    private FieldSetMapper<StudentDTO> createStudentInformationMapper() {
        BeanWrapperFieldSetMapper<StudentDTO> studentInformationMapper = new BeanWrapperFieldSetMapper<>();
        studentInformationMapper.setTargetType(StudentDTO.class);
        return studentInformationMapper;
    }
}

Upvotes: 0

Tiago Luna
Tiago Luna

Reputation: 111

Considering that your project uses Java 8, you can simply manipulate the file data using stream (with line()) and map them to the desired class (using map()), in this case, MonsterAttack. It would be something like this:

public void readFromFile(String path) throws Exception {
    final File definitions = Paths.get(path).toFile();
    final BufferedReader reader = new BufferedReader(new FileReader(definitions));

    monsterAttacks = reader.lines().map(line -> {
        String[] entry = line.split(",");
        return new MonsterAttack(Integer.parseInt(entry[0]), entry[1], entry[2], entry[3], entry[4]);
    }).collect(Collectors.toList());

    reader.close();
}

I hope it helps.

Upvotes: 0

Stan Van Der Bend
Stan Van Der Bend

Reputation: 62

I highly recommend to just use a file reader for this, it has everything u will need and the streams collection that comes with Java 8 offers some nice operations you can perform on the given input.

Here is the code:

    final File definitions = Paths.get("some/dir", "monster_definitions.txt").toFile();
    final BufferedReader reader = new BufferedReader(new FileReader(definitions));

    final String[] entries = reader.lines().collect(Collectors.joining()).split(")");

    for(String entry : entries){

        final String[] data = entry.substring(1, entry.lastIndexOf(entry)-1).split(",");

        final int id = Integer.parseInt(data[0]);
        final String date = data[1];
        final String name = data[2];
        final String location = data[3];
        final String reporter = data[4];

        monsterAttacks.add(new MonsterAttack(id, date, name, location, reporter));
    }

    reader.close();

Now, we first get a stream of all the lines and we collect each separate line into one final string. This string we split by ")" as this is the end mark of each individual entry. Then we loop through each entry and return a substring of the entry. Starting at index 1 and ending at the final index minus 1, this we do solely to get rid of the "(" and ")". Now we got our raw entry containing all the information we need to cache the definition. We split the entry by using "," as the regex and thus get an array of each individual data entry.

However, I really encourage you to use something as JSON for this kind of definition serialization and deserialization. It's much easier to work with and offers a lot more flexibility in operating with the data.


Edit: just noticed that u didn't have any splitters for each entry. Unless every entry it just split by a line break. In that case, u could just do something like this: `

final List<String> entries = new ArrayList<>(reader.lines().collect(Collectors.toList()));

            for(String entry : entries){`

Upvotes: 1

Related Questions