0

I want to read from a text file which contains information about books. The information about the book should be put in an array. I understand I need to split.

The content in the text file looks like:

ISBN: 9781119846475
category: Computers
author: Andy Rathbone
title: Windows 11 For Dummies
language: English
pages: 464
price: 25
itemsInStock:24

ISBN: 9781118506851
category: Music
author: Alistair Wood
title: Ukulele Exercises For Dummies
language: English
pages: 272
price: 23
itemsInStock:5

I have tried something like this, but it doesn't work and I feel I'm thinking wrong.

BookClass bookArray [] = new BookClass[10];
try {
    String bookInfo = "books.txt";
    String line ="";            
    BufferedReader reader = new BufferedReader(new FileReader (bookInfo));
            
    while ((line = reader.readLine()) != null) {    
        String[] bookText = line.split("//n ");     
        ISBN = bookText[0].split(": ")[1];      
        category = bookText[1].split(": ")[1];
        author = bookText[2].split(": ")[1];
        title = bookText[3].split(": ")[1];
        language = bookText[4].split(": ")[1];
        pages = bookText[5].split(": ")
        price =  Integer.parseInt(bookText[7].split(": ")[1]);
        itemesInStock =  Integer.parseInt(bookText[8].split(": ")[1]);

        BookClass bookObj = new BookClass(ISBN, category, author, title, language, pages,                    
                                        price, itemesInStock);
        bookArray[counter] = bookObj;
        counter += 1;
    }
    reader.close();
}
8
  • "but it doesn't work" Can you be more specific there? What result did you expect? What result did you get? Do you get an error? have you tried debugging your code? Commented Jun 2, 2022 at 6:24
  • @Stultuske I got indexoutofBound execption on the line with category = bookText[1].split(": ")[1]; If I remeber right. Commented Jun 2, 2022 at 6:26
  • "If I remember right", just copy paste the error. IndexOutOfBounds means you are trying to get an element that doesn't exist. Might be bookText[1], might be the result of that split[1]. Commented Jun 2, 2022 at 6:32
  • 2
    The main issue here is that you are reading the files one line at a time, but you are processing content as if you are reading one book at a time. Your code should have the following steps: 1.Read the ENTIRE file into a string 2. Separate the string from step 1 into an array of strings, each string in the array representing data for one book. 3. For each book string, evaluate the different properties and create its BookClass equivalent. Commented Jun 2, 2022 at 6:43
  • 1
    The last field of your input data, itemsInStock is inconsistent, using one character (COLON) as a delimiter rather than two (COLON & SPACE). Is that correct, or is that a typo? Commented Jun 2, 2022 at 6:45

2 Answers 2

1

Faulty index numbering

One specific problem is that your index counting is incorrect. Rather than use indexes of 0 to 7, you use 0 to 8 while skipping # 6.

Alternative implementation

Here is my implementation. A bit more concise and simpler, though basically the same idea as yours. I assume the entire data file can fit in memory.

Let's define your input data as a string, for simplicity.

I corrected the last field of each book to use a COLON SPACE as delimiter rather than just COLON.

String input =
        """
        ISBN: 9781119846475
        category: Computers
        author: Andy Rathbone
        title: Windows 11 For Dummies
        language: English
        pages: 464
        price: 25
        itemsInStock: 24
                        
        ISBN: 9781118506851
        category: Music
        author: Alistair Wood
        title: Ukulele Exercises For Dummies
        language: English
        pages: 272
        price: 23
        itemsInStock: 5
        """;

Define a class as a record to hold the data parsed from each book entry.

record Book(
        String isbn ,
        String category ,
        String author ,
        String title ,
        String language ,
        int pages ,
        BigDecimal price ,
        int itemsInStock

) { }

Split the overall input string into an array of strings. Each string represents one book.

String[] bookInputs = input.split( "\n\n" );

Make a list where we will store our resulting Book objects.

List < Book > books = new ArrayList <>( bookInputs.length );

Give a name to the COLON & SPACE characters delimiting the key-value pair in each line.

final String FIELD_DELIMITER = ": ";

Loop each book entry string. Split into individual lines.

Each line is a key-value pairing, delimited by a pair of characters, COLON & SPACE. So split on that pair. We always want the second item of that pair. With annoying zero-based index counting, that means we always want index 1.

for ( String bookInput : bookInputs )
{
    String[] lines = bookInput.split( "\n" );
    Book book =
            new Book(
                    lines[ 0 ].split( FIELD_DELIMITER )[ 1 ] ,
                    lines[ 1 ].split( FIELD_DELIMITER )[ 1 ] ,
                    lines[ 2 ].split( FIELD_DELIMITER )[ 1 ] ,
                    lines[ 3 ].split( FIELD_DELIMITER )[ 1 ] ,
                    lines[ 4 ].split( FIELD_DELIMITER )[ 1 ] ,
                    Integer.parseInt( lines[ 5 ].split( FIELD_DELIMITER )[ 1 ] ) ,
                    new BigDecimal( lines[ 6 ].split( FIELD_DELIMITER )[ 1 ] ) ,
                    Integer.parseInt( lines[ 7 ].split( FIELD_DELIMITER )[ 1 ] )
            );
    books.add( book );
}

Dump to console.

System.out.println( "books = " + books );

books = [Book[isbn=9781119846475, category=Computers, author=Andy Rathbone, title=Windows 11 For Dummies, language=English, pages=464, price=25, itemsInStock=24], Book[isbn=9781118506851, category=Music, author=Alistair Wood, title=Ukulele Exercises For Dummies, language=English, pages=272, price=23, itemsInStock=5]]

This code is for demonstration only. In real work I would do a bunch of data validation.

Sign up to request clarification or add additional context in comments.

2 Comments

@SayanBhattacharya See 6th line of the linked Java JEP document. Java 16 and later includes the records feature. Used here for brevity. You could just as well declare a conventional class.
Thank you very much @Basil Bourque, however I am supposed to understand how to do it without using arraylist. And yes it was a typo mistake, it should have been a space between on itemsInStock: 5 as well as the mistake with skipping [6]. I also realize that I should had written that I do want to exclude the text before : like ISBN, category, author, title, language, pages, price and itemsInStock.
0

As its name implies, reader.readLine() reads one line of text, so there is no "\n" in the line that it returns.

I would do something like this:

private static final Pattern RE = Pattern.compile("^\\s*([^\\s:]+)\\s*:\\s*(.+)$");

...

    List<BookClass> bookList = new ArrayList<>();
    String bookInfo = "books.txt";
    try (FileInputStream stream = new FileInputStream(bookInfo);
            Reader reader = new InputStreamReader(stream, "UTF-8");
                BufferedReader in = new BufferedReader(reader)) {
        Map<String,String> currentBook = new HashMap<>();
        String line;            
        while ((line = in.readLine()) != null) {
            if (line.trim().length() == 0) {
                // empty line: record separator
                if (!currentBook.isEmpty()) {
                    BookClass bookObj = makeBook(currentBook);
                    bookList.add(bookObj);
                    currentBook.clear();
                }
            } else {
                Matcher matcher = RE.matcher(line);
                if (matcher.matches()) {
                    currentBook.put(matcher.group(1), matcher.group(2));
                }
            }
        }
        if (!currentBook.isEmpty()) {
            BookClass bookObj = makeBook(currentBook);
            bookList.add(bookObj);
        }
        System.out.println(bookList);
    } catch (IOException ex) {
        Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
    }

...

private static BookClass makeBook(Map<String, String> currentBook) {
    BookClass bookObj = new BookClass(
            currentBook.get("ISBN"),
            currentBook.get("category"),
            currentBook.get("author"),
            currentBook.get("title"),
            currentBook.get("language"),
            Integer.parseInt(currentBook.get("pages")),
            Double.parseDouble(currentBook.get("price")),
            Integer.parseInt(currentBook.get("itemsInStock")));
    return bookObj;
}

1 Comment

I´m still struggeling to understand, so if anyone has any helpful ideas, that would be wonderful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.