lancer
lancer

Reputation: 133

Search a file for a String and return that String if found

How can you search through a txt file for a String that the user inputs and then return that String to the console. I've written some code that doesn't work below, but I hope it can illustrate my point...

public static void main(String[] args) {
  searchforName();
}

   private static void searchForName() throws FileNotFoundException {
    File file = new File("leaders.txt");
    Scanner kb = new Scanner(System.in);
    Scanner input = new Scanner(file);

    System.out.println("Please enter the name you would like to search for: ");
    String name = kb.nextLine();


    while(input.hasNextLine()) {
        System.out.println(input.next(name));
    }
}

The "leaders.txt" file contains a list of names.

Upvotes: 9

Views: 95236

Answers (3)

LuCio
LuCio

Reputation: 5173

The following Java 7+ solution has a main advantage.

private static void searchForName() throws IOException {
    System.out.println("Please enter the name you would like to search for: ");
    Scanner kb = new Scanner(System.in);
    String name = kb.nextLine();

    List<String> lines = Files.readAllLines(Paths.get("leaders.txt"));
    for (String line : lines) {
        if (line.contains(name)) {
            System.out.println(line);
        }
    }
}

It's not shorter than the the code from this answer. The main point is, when we open a File we have an open resource and we have to care about closing it. Otherwise it might pose a resource leak.

As of Java 7 the try-with-resources statement handles closing of resources. So opening a Scanner backed by a file would look like that:

try (Scanner scanner = new Scanner("leaders.txt")) {
    // using scanner
}

Using Files.readAllLines we don't need to care about closing the file since this method (JavaDoc)

ensures that the file is closed when all bytes have been read or an I/O error, or other runtime exception, is thrown.

If the first occourance of a String is needed only, the following Java 8+ code does the job in few lines:

protected static Optional<String> searchForName(String name) throws IOException {
    try (Stream<String> lines = Files.lines(Paths.get("leaders.txt"))) {
        return lines.filter(line -> line.contains(name)).findFirst();
    }
}

It returns an Optional indicating that there might be an empty result. We use it i.e. as follows:

private static void searchForName() throws IOException {
    System.out.println("Please enter the name you would like to search for: ");
    Scanner kb = new Scanner(System.in);
    String name = kb.nextLine();

    Optional<String> result = searchForName(name);
    result.ifPresent(System.out::println);
}

Upvotes: 2

Aqeel Ashiq
Aqeel Ashiq

Reputation: 2185

Scanner is way too slow. Run the following code, and see the differences. Searched in 750 MB file, and BufferedReader is 10 times faster than Scanner on average.

package uk.co.planetbeyond.service.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Date;
import java.util.HashSet;
import java.util.Scanner;

public class SearchTextInFile
{
    public static void main(String[] args) throws IOException
    {
        // First write a file, with large number of entries
        writeFile("/home/aqeel/temp/subscribers_files.csv");

        long scannerSearchMillis = 0;
        long brSearchMillis = 0;

        int iterations = 5;

        // Now search random strings five times, and see the time taken
        for (int i = 0; i < iterations; i++)
        {
            String msisdn = String.valueOf(923000000000l + ((long) (Math.random() * 40000000)));

            System.out.println("ITERATION " + i);
            System.out.print("Search " + msisdn + " using scanner");
            Date d1 = new Date();
            searchUsingScanner("/home/aqeel/temp/subscribers_files.csv", msisdn);
            Date d2 = new Date();

            long millis = (d2.getTime() - d1.getTime());
            scannerSearchMillis += millis;
            System.out.println(" | " + (millis / 1000) + " Seconds");
            System.out.println("==================================================================");
            System.out.print("Search " + msisdn + " using buffered reader");
            d1 = new Date();
            searchUsingBufferedReader("/home/aqeel/temp/subscribers_files.csv", msisdn);
            d2 = new Date();
            millis = d2.getTime() - d1.getTime();
            brSearchMillis += millis;
            System.out.println(" | " + (millis / 1000) + " Seconds");
            System.out.println("==================================================================");
            System.out.println("==================================================================");
            System.out.println("==================================================================");
            System.out.println("==================================================================");
        }

        System.out.println("Average Search time using Scanner " + (scannerSearchMillis / (iterations * 1000.0)) + " Seconds");
        System.out.println("Average Search time using BufferedReader " + (brSearchMillis / (iterations * 1000.0)) + " Seconds");
    }

    public static void writeFile(String path)
    {
        BufferedWriter csvWriter = null;
        HashSet<Integer> additions = new HashSet<Integer>();
        try
        {
            csvWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path)));

            for (int i = 0; i < 40000000; i++)
            {
                int addition = (int) (Math.random() * 40000000);
                additions.add(addition);

                if (i % 20000 == 0)
                {
                    System.out.println("Entries written : " + i + " ------ Unique Entries: " + additions.size());
                    csvWriter.flush();
                }

                long msisdn = 923000000000l + addition;
                csvWriter.write(String.valueOf(msisdn) + "|" + String.valueOf((int) (Math.random() * 131)) + "\r\n");
            }

            csvWriter.flush();

            System.out.println("Unique Entries written : " + additions.size());
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        finally
        {
            if (csvWriter != null)
            {
                try
                {
                    csvWriter.close();
                }
                catch (IOException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }

    public static String searchUsingScanner(String filePath, String searchQuery) throws FileNotFoundException
    {
        searchQuery = searchQuery.trim();
        Scanner scanner = null;
        try
        {
            scanner = new Scanner(new File(filePath));
            while (scanner.hasNextLine())
            {
                String line = scanner.nextLine();
                if (line.contains(searchQuery))
                {
                    return line;
                }
                else
                {
                }
            }
        }
        finally
        {
            try
            {
                if (scanner != null)
                    scanner.close();
            }
            catch (Exception e)
            {
                System.err.println("Exception while closing scanner " + e.toString());
            }
        }

        return null;
    }

    public static String searchUsingBufferedReader(String filePath, String searchQuery) throws IOException
    {
        searchQuery = searchQuery.trim();
        BufferedReader br = null;

        try
        {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
            String line;
            while ((line = br.readLine()) != null)
            {
                if (line.contains(searchQuery))
                {
                    return line;
                }
                else
                {
                }
            }
        }
        finally
        {
            try
            {
                if (br != null)
                    br.close();
            }
            catch (Exception e)
            {
                System.err.println("Exception while closing bufferedreader " + e.toString());
            }
        }

        return null;
    }
}

Upvotes: 5

Amir Afghani
Amir Afghani

Reputation: 38511

You can create a seperate Scanner to read the file line by line and do a match that way...

final Scanner scanner = new Scanner(file);
while (scanner.hasNextLine()) {
   final String lineFromFile = scanner.nextLine();
   if(lineFromFile.contains(name)) { 
       // a match!
       System.out.println("I found " +name+ " in file " +file.getName());
       break;
   }
}

With regards to whether you should use a Scanner or a BufferedReader to read the file, read this answer.

Upvotes: 16

Related Questions