简体   繁体   中英

Java: How do I iterate through a file with multiple lines, then extract specific lines after filtering delimiters?

Clarification: I have a text file with multiple lines and I want to separate specific lines into fields for an object.

I have been banging my head against a wall for about 3 days now, and I feel as if I'm overthinking this.

import java.io.*;
import java.util.*;
public class ReadFile {

    public static void main(String[] args) throws FileNotFoundException {
        String fileName = null;


        Scanner input = new Scanner(System.in);
        System.out.print("Enter file path: ");
        fileName = input.nextLine();      
        input.close();
        String fileText = readFile(fileName);
        System.out.println(fileText);

    }

    public static String readFile(String fileName) throws FileNotFoundException {
        String fileText = "";
        String lineText = "";

        File newFile = new File(fileName);
        if (newFile.canRead()) {
            try (Scanner scanFile = new Scanner(newFile)) {
                while (scanFile.hasNext()) {
                    lineText = scanFile.nextLine();
                    
                    if (lineText.startsWith("+")) {

                     }
                    else { 
                        fileText = fileText + lineText + "\n";
                    }
                }
            } catch (Exception e) {
                System.out.println(e);
            }
        } else {
            System.out.println("No file found. Please try again.");
        }
        
        return fileText;
    }

}

My goal is to take a file that looks similar to this (this is the whole file, imagine a.txt with exactly this in it):

Name of Person
----
Clothing:
Graphic TeeShirt
This shirt has a fun logo of
depicting stackoverflow and a horizon.
****
Brown Slacks
These slacks reach to the floor and
barely cover the ankles.
****
Worn Sandals
The straps on the sandals are frayed,
and the soles are obviously worn.
----

Then I need to extract the top line (eg: "Graphic TeeShirt") as a type of clothing the object is wearing, then "This shirt has a fun [...]" as the description of that object.

I have another.java with setters/getters/constructors, but I can't figure out how to iterate through the text file.

Edit: I know I loop through each line, but I need to create an object that has the person's name as a field, the item name (Graphic TeeShirt) as a field, then the description under the item as the next field. Then the next object will be a new object with person's name as a field, the next item (Brown Slacks) as a field, then the description as a field.

I don't know how to separate the lines in to the fields I need.

As I mentioned, the data file format is lousy, which is the real source of the problem, but your delimiters can be used to help out a little. You might approach the problem this way. Obviously don't dump your code like I've done into main but this might start you off. You still need to separate the clothing names from their descriptions but you should get the idea from the below. You can then start making a pojo out of the data. Pass the path to your data file to this app and look out for the metadata debug outputs of 'Name' and 'Item'.

import java.util.Scanner;
import java.nio.file.Paths;

public class PersonParser {
    public static void main(String[] args) {
        try {
            try (Scanner scPeople = new Scanner(Paths.get(args[0]))) {
                scPeople.useDelimiter("----+");
                int tokenCount = 0;
                while (scPeople.hasNext()) {
                    String token = scPeople.next();
                    if (tokenCount % 2 == 0) {
                        System.out.printf("Name: %s", token);
                    } else {
                        // Parse clothing
                        Scanner scClothing = new Scanner(token);
                        scClothing.useDelimiter("\\*\\*\\*+");
                        while (scClothing.hasNext()) {
                            String item = scClothing.next();
                            System.out.printf("Item: %s", item);
                        }
                    }
                    tokenCount++;
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
    }

}

The following code is according to the details in your question, namely:

  1. The sample file in your question is the entire file.
  2. You want to create instances of objects that have the following three attributes:
    • Person's name.
    • Name of an item of clothing.
    • Description of that item.

Note that rather than ask the user for the name of the file, I simply use a hard-coded file name. Also note that method toString , in the below code, is simply for testing purposes. The code also uses try-with-resources and method references .

public class ReadFile {
    private static final String DELIM = "****";
    private static final String LAST = "----";
    private String name;
    private String item;
    private String description;

    public void setName(String name) {
        this.name = name;
    }

    public String getItem() {
        return item;
    }

    public void setItem(String item) {
        this.item = item;
    }

    public void setDescription(String description) {
        this.description = description;
    }
    public String toString() {
        return String.format("%s | %s | %s", name, item, description);
    }

    public static void main(String[] strings) {
        try (FileReader fr = new FileReader("clothing.txt");
             BufferedReader br = new BufferedReader(fr)) {
            String line = br.readLine();
            String name = line;
            br.readLine();
            br.readLine();
            line = br.readLine();
            String item = line;
            List<ReadFile> list = new ArrayList<>();
            ReadFile instance = new ReadFile();
            instance.setName(name);
            instance.setItem(item);
            line = br.readLine();
            StringBuilder description = new StringBuilder();
            while (line != null && !LAST.equals(line)) {
                if (DELIM.equals(line)) {
                    instance.setDescription(description.toString());
                    list.add(instance);
                    instance = new ReadFile();
                    instance.setName(name);
                    description.delete(0, description.length());
                }
                else {
                    if (instance.getItem() == null) {
                        instance.setItem(line);
                    }
                    else {
                        description.append(line);
                    }
                }
                line = br.readLine();
            }
            if (description.length() > 0) {
                instance.setDescription(description.toString());
                list.add(instance);
            }
            list.forEach(System.out::println);
        }
        catch (IOException xIo) {
            xIo.printStackTrace();
        }
    }
}

Running the above code produces the following output:

Name of Person | Graphic TeeShirt | This shirt has a fun logo ofdepicting stackoverflow and a horizon.
Name of Person | Brown Slacks | These slacks reach to the floor andbarely cover the ankles.
Name of Person | Worn Sandals | The straps on the sandals are frayed,and the soles are obviously worn.

It's not clear what you want to achieve and what is your issue exactly. You said that you can't figure out how to iterate through a text file, so let's dive into this fairly straightforward task.

In general, you have a valid, but the overcomplicated method for reading a file. Modern versions of Java provide a lot simpler methods and it's better to use them (only if you're not implementing some test task to understand how everything is working under the hood).

Please see my example below for reading a file line by line using Java NIO and Streams APIs:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
import java.util.stream.Stream;

public class Test {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("Enter file path: ");
        String fileName = input.nextLine();
        input.close();
        
        Path path = Paths.get(fileName);
        try (Stream<String> lines = Files.lines(path)) {
            lines.filter(line -> {
                // filter your lines on some predicate
                return line.startsWith("+");
            });
            // do the mapping to your object
        } catch (IOException e) {
            throw new IllegalArgumentException("Incorrect file path");
        }
    }
}

This should allow you to filter the lines from your files based on some predicate and later to the mapping to your POJO if you intend to do so.

If you have any other issues besides reading the file and filtering its content, please add clarification to your questions. Preferably, with examples and test data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM