Aria

Jak posortować linie w pliku tekstowym (Java)?

Na Pulpicie mam plik pl.dic. Plik (UTF-8) jest słownikiem języka polskiego, który ma 51,3 MB i 3 638 108 linii.
Każda linia to jedno słowo.

Słownik służy mi w IntelliJ do sprawdzania pisowni w komentarzach i javadocs. Konieczne jest stałe dodawanie nowych słów.

Powstaje problem, który można rozłożyć na kilka zagadnień:

  • Jak najłatwiej dodać słowa do pliku?
  • Jak sprawdzić czy dodane słowa nie są duplikatami słów w pliku?
  • Jak posortować słowa w pliku uwzględniając porządek alfabetu języka polskiego z założeniem, że duże litery
    nie wpływają na położenie słowa?
  • Jak zrobić to bezpiecznie – bez ryzyka utraty danych?

Jak najłatwiej dodać słowa do pliku?

Można dopisac słowa otwierając plik w edytorze Notepad++ (W Notatniku plik otwiera się znacznie dłużej).

Dopisanie do arraylisty

Jesteśmy programistami. Nowe słowa dopiujemy do arraylisty. Potem uruchamiamy klasę AddText i dodajemy słowa z
arraylisty do słownika. Słownik wymaga posortowania

Klasa AddText
            package filesorting;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;

public class AddText {
    public static void main(String[] args){
        Path plik = Paths.get("C:/Users/Jacek/Desktop/pl.dic");
        Charset charset = StandardCharsets.UTF_8;
        ArrayList<String> words = new ArrayList<>();
        words.add("B\u00E9zier");
        //----
        try {
            Files.write(plik, words, charset, StandardOpenOption.APPEND);
        } catch (IOException e) {
            e.printStackTrace();
        }


    }
}
        

Dopisanie do pliku tekstowego

Na Pulpicie mamy dodatkowy pusty plik words.txt UTF-8.
Do pliku dopisujemy słowa. Uruchamiamy klase AddTextFromFile, która:

  • Wczytuje linie z pliku words.txt do arraylisty
  • Zapisuje słowa z arraylisty do pliku pl.dic
  • Zeruje plik words.txt

Plik słownika wymaga posortowania

Klasa AddTextFromFile
          
package filesorting;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.Collator;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

public class AddTextFromFile {
    public static void main(String[] args) {
        Instant start = Instant.now();
        Path dicpath1 = Paths.get("C:/Users/Jacek/Desktop/words.txt");
        Path dicpath2 = Paths.get("C:/Users/Jacek/Desktop/pl.dic");
        Charset charset = StandardCharsets.UTF_8;
        try {
            List<String> list = Files.readAllLines(dicpath1, charset);
            Files.write(dicpath2, list, charset, StandardOpenOption.APPEND);
            Files.writeString(dicpath1, "", StandardOpenOption.TRUNCATE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Instant end = Instant.now();
        long millis = Duration.between(start, end).toMillis();
        System.out.println(millis);
    }
}
        

Sortowanie bez sprawdzanie duplikatów

Do posortowania pliku użyjemy klasy SortFile

Klasa kolejno:

  • Tworzy ścieżki do pliku słownika i pliku pomocniczego
  • Wczytuje zawartość pliku słownika do arraylisty
  • Tworzy polski kolator
  • Ustawia siłę kolatora (spośób sortowania)
  • Sortuje arraylistę przy użyciu kolatora
  • Zapisuje zawartość arraylisty do pliku rezerwowego
  • Usuwa plik słownika
  • Zmienia nazwę pliku rezerwowego na nazwę słownika
Klasa SortFile

Uwaga. Uzycie kolatora powoduje drastyczne przedłużenie czasu sortowania. Sortowanie trwa przeciętnie ok.
70 sek. Przy sortowaniu bez kolatora czas jest rzedu 500 ms.

            package filesorting;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.Collator;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
//Nie weryfikuje czy dodawane słowo jest duplikatem
public class SortFile {
    public static void main(String[] args) {
        Instant start = Instant.now();
        Path dicpath1 = Paths.get("C:/Users/Jacek/Desktop/pl.dic");
        Path dicpath2 = Paths.get("C:/Users/Jacek/Desktop/pl1.dic");
        Charset charset = StandardCharsets.UTF_8;
        try {
            List<String> list = Files.readAllLines(dicpath1, charset);
            Collator col = Collator.getInstance(new Locale("pl", "PL"));
            col.setStrength(Collator.SECONDARY);
            Objects.requireNonNull(list).sort(col);
            Files.write(dicpath2, list, charset, StandardOpenOption.CREATE_NEW);
            Files.deleteIfExists(dicpath1);
            Files.move(dicpath2, dicpath2.resolveSibling("pl.dic"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        Instant end = Instant.now();
        long millis = Duration.between(start, end).toMillis();
        System.out.println(millis);
    }
}
        

Sortowanie ze sprawdzaniem duplikatów

Do posortowania użyjemy klasy SortFileFull

Klasa kolejno

  • Tworzy ścieżki do pliku słownika i pliku pomocniczego
  • Wczytuje zawartość pliku słownika do arraylisty
  • Wczytuje arraylistę do zbioru TreeSet. Duplikaty są automatycznie pomijane.
  • Przepisuje zbiór z powrotem do arraylisty.
  • Tworzy polski kolator
  • Ustawia siłę kolatora (spośób sortowania)
  • Sortuje arraylistę przy użyciu kolatora
  • Zapisuje zawartość arraylisty do pliku rezerwowego. Plik jest tworzony i nie powinien wcześniej istnieć.
  • Usuwa plik słownika
  • Zmienia nazwę pliku rezerwowego na nazwę słownika
Klasa SortFileFull

Uwaga. Użycie kolatora powoduje drastyczne przedłużenie czasu sortowania.
Przpisywanie arraylisty do zbioru i zbioru do arraylisty również przedłuża czas sortowania.

Oczekiwanie na posortowanie pliku trwa 90 – 100 s.

            package filesorting;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.text.Collator;
import java.time.Duration;
import java.time.Instant;
import java.util.*;

public class SortFileFull {
    //Odrzuca ewentualne duplikaty
    public static void main(String[] args) {
        Instant start = Instant.now();
        Path dicpath1 = Paths.get("C:/Users/Jacek/Desktop/pl.dic");
        Path dicpath2 = Paths.get("C:/Users/Jacek/Desktop/pl1.dic");
        Charset charset = StandardCharsets.UTF_8;
        try {
            List<String> list = Files.readAllLines(dicpath1, charset);
            TreeSet<String> ts = new TreeSet<>(Objects.requireNonNull(list));
            ArrayList<String> al = new ArrayList<>(ts);
            Collator col = Collator.getInstance(new Locale("pl", "PL"));
            col.setStrength(Collator.SECONDARY);
            al.sort(col);
            Files.write(dicpath2, al, charset, StandardOpenOption.CREATE_NEW);
            Files.deleteIfExists(dicpath1);
            Files.move(dicpath2, dicpath2.resolveSibling("pl.dic"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        Instant end = Instant.now();
        long millis = Duration.between(start, end).toMillis();
        System.out.println(millis);
    }
}