2017-10-02 1 views
1

Ich habe Probleme mit dieser Methode. Die Methode soll eine Textdatei für eine Reihe von Daten lesen (Attack ID [int], Datum [String gespeichert im Format MM/DD/YYYY], Name des Monsters [String], Ort [String] und Reporter von Der Angriff [String]) wird durch Kommata getrennt und diese Werte in eine ArrayList mit dem Namen monsterAttacks eingetragen. Jedes Mal, wenn ich diese Methode ausführe, erhalte ich eine InputMismatchException. Ich habe das Gefühl, dass es etwas mit dem Datum zu tun hat, aber ich bin mir nicht sicher, wo oder wie in diesem Fall die String-Methode split() verwendet wird. Wie kann ich das richtig machen?Java lesen Strings aus einer Datei

Haftungsausschluss: Dies ist Teil einer Hausaufgabe.

Vielen Dank im Voraus.

Edit: Beispieldaten aus Textdatei:

23,12/23/1994, Dracula, Kalifornien, 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(); 
    } 

} 
+0

Könnten Sie ein Beispiel der Daten in der Datei setzen? –

+0

@TiagoLuna Natürlich. Ich habe es einfach hinzugefügt. –

+0

Danke, @ max-orozco. Ich habe eine Lösung für Ihr Problem geschrieben, die nur Operationen über einen Stream verwendet. Bitte überprüfe meine Antwort. Ich hoffe, es hilft. –

Antwort

1

Sie haben uns gesagt, dass Ihre Daten

durch Komma getrennt ist

Wenn ja, dann müssten Sie diese Token-Trennzeichen berücksichtigen. Eine Möglichkeit, hier zu verfahren wäre, nur in einer ganzen Zeile gelesen und dann durch Komma geteilt, um jeden Begriff zuzugreifen:

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(); 
} 
1

ich sehr empfehlen, nur eine Datei Leser für diese, es hat alles u müssen und Die Stream-Sammlung, die mit Java 8 geliefert wird, bietet einige nette Operationen, die Sie mit der gegebenen Eingabe ausführen können. Hier

ist der 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(); 

Jetzt bekommen wir zuerst einen Strom von allen Linien und wir sammeln jede einzelne Zeile in eine letzte Saite. Diese Zeichenfolge teilen wir durch ")", da dies die Endmarke jedes einzelnen Eintrags ist. Dann durchlaufen wir jeden Eintrag und geben einen Teilstring des Eintrags zurück. Beginnend bei Index 1 und endend bei dem finalen Index minus 1, tun wir dies nur, um "(" und ")" loszuwerden. Jetzt haben wir unseren rohen Eintrag mit allen Informationen, die wir zum Zwischenspeichern der Definition benötigen. Wir teilen den Eintrag auf, indem wir "," als Regex verwenden und somit ein Array jedes einzelnen Dateneintrags erhalten.

Allerdings ermutige ich Sie wirklich, etwas wie JSON für diese Art der Definition Serialisierung und Deserialisierung zu verwenden. Es ist viel einfacher zu arbeiten und bietet viel mehr Flexibilität im Umgang mit den Daten.


Edit: gerade bemerkt, dass Sie keine Splitter für jeden Eintrag hatten. Es sei denn, jeder Eintrag teilt sich nur durch einen Zeilenumbruch auf. In diesem Fall könnte u nur so etwas tun: `

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

      for(String entry : entries){` 
+0

Der ganze Zweck der Verwendung eines Streams besteht darin, das Lesen Ihrer gesamten Eingabe (Datei) in den Speicher zur Verarbeitung zu vermeiden. Dieser Zweck wurde durch sofortiges Aufrufen der "Collect" -Methode rückgängig gemacht. Nun ist es vielleicht wahr, dass dies mit dem Aufruf 'monsterAttacks.add (...)' irgendwie passieren würde, aber es wäre vielleicht besser, das in einer Java-8-Stream-Pipeline von Anfang bis Ende zu behalten. Ich finde nur, dass eine "for" -Schleife, die einem Stream folgt, nicht geeignet ist. – YoYo

+0

@YoYo Ich stimme zu, am besten wäre es, alle notwendigen Operationen durchzuführen, ohne den Stream zu verlassen. Allerdings scheint der Themenanfänger ein bestimmtes Hausaufgabenproblem zu haben und Streams können ein wenig einschüchternd wirken, wenn Sie mit ihnen nicht vertraut sind. Vor allem in einigen wunderschönen One-Liner: D –

+0

Der Punkt ist nicht, diese wunderschönen Einzeiler zu schreiben, wie Sie sie nennen, und wie sie oft sind, aber zu vermeiden, eine TB-Datei im Speicher zu lesen, so dass Sie es verarbeiten können eine zweite Phase. Dies wird umso wichtiger, wenn Sie in Umgebungen wie Apache-Spark mit RDDs arbeiten. Prinzipien für gute Praxis. Dass man sie als Einzeiler schreiben kann, ist nur ein Nebeneffekt. Dennoch gelten Ihre Punkte im Zusammenhang mit der Posterabsicht. – YoYo

0

Bedenkt man, dass Ihr Projekt verwendet Java 8, können Sie einfach die Dateidaten mit Strom manipulieren (mit line()) und ordnet sie in der gewünschten Klasse (mit map()), in diesem Fall MonsterAttack.Es wäre etwa so:

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(); 
} 

Ich hoffe es hilft.

0

Einige gute Antworten wurden bereits gegeben, ich wollte nur eine "professionellere" Lösung für den Fall, dass Sie eine Entwicklung einer strukturierten Anwendung suchen, dann betrachten Spring Batch Flachfeile Leser here.

Obwohl ich nicht verrückt bin weiß ich, das ist ziemlich viel Aufwand und ich verstehe, dass dies eine Hausaufgabe und möglicherweise eine einfache Java-Anwendung ist. Ich denke nur, dass dies eine schöne Referenz für die Zukunft ist.

Mit Flat File Reader/Writer können Sie Ihre Flatfile in ein POJO (Plain Old Java Object) abbilden und Sie können Spring Batch auch zum Verketten von Operationen verwenden, um Ihrer Batch-Anwendung eine schönere Struktur zu geben.

Hier ist ein einfaches Snippet, wie es funktioniert (aus dem obigen Link):

@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; 
    } 
} 
Verwandte Themen