Java: Jak czytać plik tekstowy

81

Chcę przeczytać plik tekstowy zawierający wartości oddzielone spacjami. Wartości są liczbami całkowitymi. Jak mogę to przeczytać i umieścić na liście tablic?

Oto przykład zawartości pliku tekstowego:

1 62 4 55 5 6 77

Chcę to mieć na liście arystokratów jako [1, 62, 4, 55, 5, 6, 77]. Jak mogę to zrobić w Javie?

aks
źródło

Odpowiedzi:

170

Możesz użyć, Files#readAllLines()aby pobrać wszystkie wiersze pliku tekstowego do pliku List<String>.

for (String line : Files.readAllLines(Paths.get("/path/to/file.txt"))) {
    // ...
}

Samouczek: Podstawowe we / wy> We / wy pliku> Czytanie, pisanie i tworzenie plików tekstowych


Możesz użyć String#split()do podzielenia a Stringna części na podstawie wyrażenia regularnego.

for (String part : line.split("\\s+")) {
    // ...
}

Samouczek: Liczby i ciągi> Ciągi znaków> Manipulowanie znakami w ciągu


Możesz użyć Integer#valueOf()do konwersji a Stringdo Integer.

Integer i = Integer.valueOf(part);

Samouczek: Liczby i ciągi> Ciągi znaków> Konwersja między liczbami a ciągami


Możesz użyć, List#add()aby dodać element do List.

numbers.add(i);

Samouczek: Interfejsy> Interfejs listy


A więc w skrócie (zakładając, że plik nie ma pustych linii ani końcowych / wiodących białych spacji).

List<Integer> numbers = new ArrayList<>();
for (String line : Files.readAllLines(Paths.get("/path/to/file.txt"))) {
    for (String part : line.split("\\s+")) {
        Integer i = Integer.valueOf(part);
        numbers.add(i);
    }
}

Jeśli jesteś już w Javie 8, możesz nawet użyć do tego Stream API , zaczynając odFiles#lines() .

List<Integer> numbers = Files.lines(Paths.get("/path/to/test.txt"))
    .map(line -> line.split("\\s+")).flatMap(Arrays::stream)
    .map(Integer::valueOf)
    .collect(Collectors.toList());

Samouczek: Przetwarzanie danych za pomocą strumieni Java 8

BalusC
źródło
1
Zauważ, że istnieją lepsze sposoby na zrobienie tego w Javie 7 i 8: stackoverflow.com/questions/4716503/ ...
Alex Beardsley
34

Java 1.5 wprowadziła Scanner klasę do obsługi danych wejściowych z pliku i strumieni.

Służy do pobierania liczb całkowitych z pliku i wygląda mniej więcej tak:

List<Integer> integers = new ArrayList<Integer>();
Scanner fileScanner = new Scanner(new File("c:\\file.txt"));
while (fileScanner.hasNextInt()){
   integers.add(fileScanner.nextInt());
}

Sprawdź jednak API. Istnieje znacznie więcej opcji radzenia sobie z różnymi typami źródeł wejściowych, różnymi ogranicznikami i różnymi typami danych.

tschaible
źródło
2
jest to o wiele łatwiejsze do zapamiętania niż buforowana kombinacja czytnika io
avanderw
18

Ten przykładowy kod pokazuje, jak czytać plik w Javie.

import java.io.*;

/**
 * This example code shows you how to read file in Java
 *
 * IN MY CASE RAILWAY IS MY TEXT FILE WHICH I WANT TO DISPLAY YOU CHANGE WITH YOUR   OWN      
 */

 public class ReadFileExample 
 {
    public static void main(String[] args) 
    {
       System.out.println("Reading File from Java code");
       //Name of the file
       String fileName="RAILWAY.txt";
       try{

          //Create object of FileReader
          FileReader inputFile = new FileReader(fileName);

          //Instantiate the BufferedReader Class
          BufferedReader bufferReader = new BufferedReader(inputFile);

          //Variable to hold the one line data
          String line;

          // Read file line by line and print on the console
          while ((line = bufferReader.readLine()) != null)   {
            System.out.println(line);
          }
          //Close the buffer reader
          bufferReader.close();
       }catch(Exception e){
          System.out.println("Error while reading file line by line:" + e.getMessage());                      
       }

     }
  }
Sajjad Khan
źródło
10

Spójrz na ten przykład i spróbuj zrobić to samodzielnie:

import java.io.*;

public class ReadFile {

    public static void main(String[] args){
        String string = "";
        String file = "textFile.txt";

        // Reading
        try{
            InputStream ips = new FileInputStream(file);
            InputStreamReader ipsr = new InputStreamReader(ips);
            BufferedReader br = new BufferedReader(ipsr);
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
                string += line + "\n";
            }
            br.close();
        }
        catch (Exception e){
            System.out.println(e.toString());
        }

        // Writing
        try {
            FileWriter fw = new FileWriter (file);
            BufferedWriter bw = new BufferedWriter (fw);
            PrintWriter fileOut = new PrintWriter (bw);
                fileOut.println (string+"\n test of read and write !!");
            fileOut.close();
            System.out.println("the file " + file + " is created!");
        }
        catch (Exception e){
            System.out.println(e.toString());
        }
    }
}
Eddinho
źródło
5

Dla zabawy, oto, co prawdopodobnie zrobiłbym w prawdziwym projekcie, w którym już używam wszystkich moich ulubionych bibliotek (w tym przypadku Guava , wcześniej znanej jako Kolekcje Google ).

String text = Files.toString(new File("textfile.txt"), Charsets.UTF_8);
List<Integer> list = Lists.newArrayList();
for (String s : text.split("\\s")) {
    list.add(Integer.valueOf(s));
}

Korzyści: Niewiele własnego kodu do utrzymania (w przeciwieństwie do np. Tego ). Edycja : Chociaż warto zauważyć, że w tym przypadku rozwiązanie Scanner firmy tschaible nie ma już kodu!

Wada: oczywiście możesz nie chcieć dodawać nowych zależności biblioteki tylko w tym celu. (Z drugiej strony, głupio byłoby nie używać guawy w swoich projektach. ;-)

Jonik
źródło
Oczywiście zamiast pętli można by użyć transform () i funkcji z Google Collections, ale IMHO byłoby mniej czytelne i nawet nie krótsze.
Jonik
4

Użyj Apache Commons (IO i Lang) do prostych / typowych rzeczy, takich jak ten.

Import:

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.ArrayUtils;

Kod:

String contents = FileUtils.readFileToString(new File("path/to/your/file.txt"));
String[] array = ArrayUtils.toArray(contents.split(" "));

Gotowe.

Chris
źródło
2

Używanie Java 7 do odczytu plików za pomocą NIO.2

Importuj te pakiety:

import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

Oto proces odczytu pliku:

Path file = Paths.get("C:\\Java\\file.txt");

if(Files.exists(file) && Files.isReadable(file)) {

    try {
        // File reader
        BufferedReader reader = Files.newBufferedReader(file, Charset.defaultCharset());

        String line;
        // read each line
        while((line = reader.readLine()) != null) {
            System.out.println(line);
            // tokenize each number
            StringTokenizer tokenizer = new StringTokenizer(line, " ");
            while (tokenizer.hasMoreElements()) {
                // parse each integer in file
                int element = Integer.parseInt(tokenizer.nextToken());
            }
        }
        reader.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Aby odczytać wszystkie wiersze pliku naraz:

Path file = Paths.get("C:\\Java\\file.txt");
List<String> lines = Files.readAllLines(file, StandardCharsets.UTF_8);
user2601995
źródło
1

Wszystkie dotychczas podane odpowiedzi obejmują czytanie pliku wiersz po wierszu, przyjmując wiersz jako plik String , a następnie przetworzenieString .

Nie ma wątpliwości, że jest to najłatwiejsze do zrozumienia podejście, a jeśli plik jest dość krótki (powiedzmy, dziesiątki tysięcy wierszy), będzie również akceptowalny pod względem wydajności. Ale jeśli plik jest długi , jest to bardzo nieefektywny sposób z dwóch powodów:

  1. Każdy znak jest przetwarzany dwukrotnie, raz podczas konstruowania String i raz podczas przetwarzania.
  2. Odśmiecacz nie będzie twoim przyjacielem, jeśli w pliku jest dużo wierszy. Tworzysz nowy Stringdla każdego wiersza, a następnie odrzucasz go, gdy przechodzisz do następnego wiersza. W końcu odśmiecacz będzie musiał pozbyć się wszystkich tych Stringobiektów, których już nie chcesz. Ktoś musi po tobie posprzątać.

Jeśli zależy Ci na szybkości, znacznie lepiej jest odczytać blok danych, a następnie przetwarzać go bajt po bajcie, a nie wiersz po wierszu. Za każdym razem, gdy zbliżasz się do końca liczby, dodajesz ją do Listbudowanej liczby .

Wyjdzie coś takiego:

private List<Integer> readIntegers(File file) throws IOException {
    List<Integer> result = new ArrayList<>();
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    byte buf[] = new byte[16 * 1024];
    final FileChannel ch = raf.getChannel();
    int fileLength = (int) ch.size();
    final MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0,
            fileLength);
    int acc = 0;
    while (mb.hasRemaining()) {
        int len = Math.min(mb.remaining(), buf.length);
        mb.get(buf, 0, len);
        for (int i = 0; i < len; i++)
            if ((buf[i] >= 48) && (buf[i] <= 57))
                acc = acc * 10 + buf[i] - 48;
            else {
                result.add(acc);
                acc = 0;
            }
    }
    ch.close();
    raf.close();
    return result;
}

Powyższy kod zakłada, że ​​jest to ASCII (chociaż można go łatwo dostosować do innych kodowań) i że wszystko, co nie jest cyfrą (w szczególności spacja lub znak nowej linii) reprezentuje granicę między cyframi. Zakłada również, że plik kończy się cyfrą niecyfrową (w praktyce ostatnia linia kończy się znakiem nowej linii), chociaż ponownie można go zmodyfikować, aby poradzić sobie z przypadkiem, w którym tak się nie dzieje.

Jest to dużo, dużo szybsze niż którekolwiek z Stringpodejść opartych na zasadzie podanych również jako odpowiedzi na to pytanie. W tym pytaniu szczegółowo zbadano bardzo podobną kwestię . Zobaczysz tam, że istnieje możliwość dalszego ulepszenia, jeśli chcesz zejść w dół po linii wielowątkowej.

bezpieczeństwo-chiastyczne
źródło
0

przeczytaj plik, a następnie zrób, co chcesz java8 Files.lines (Paths.get ("c: //lines.txt")). collect (Collectors.toList ());

Ran Adler
źródło