Java Le moyen le plus rapide de lire un fichier texte avec 2 millions de lignes
Actuellement, j'utilise scanner/filereader et tout en utilisant hasnextline. Je pense que cette méthode n'est pas très efficace. Existe-t-il une autre méthode pour lire un fichier avec une fonctionnalité similaire?
public void Read(String file) {
Scanner sc = null;
try {
sc = new Scanner(new FileReader(file));
while (sc.hasNextLine()) {
String text = sc.nextLine();
String[] file_Array = text.split(" ", 3);
if (file_Array[0].equalsIgnoreCase("case")) {
//do something
} else if (file_Array[0].equalsIgnoreCase("object")) {
//do something
} else if (file_Array[0].equalsIgnoreCase("classes")) {
//do something
} else if (file_Array[0].equalsIgnoreCase("function")) {
//do something
}
else if (file_Array[0].equalsIgnoreCase("ignore")) {
//do something
}
else if (file_Array[0].equalsIgnoreCase("display")) {
//do something
}
}
} catch (FileNotFoundException e) {
System.out.println("Input file " + file + " not found");
System.exit(1);
} finally {
sc.close();
}
}
Vous constaterez que BufferedReader.readLine()
est aussi rapide que vous le souhaitez: vous pouvez lire des millions de lignes à la seconde. Il est plus probable que le fractionnement et la gestion de votre chaîne posent les problèmes de performances que vous rencontrez.
Scanner
ne peut pas être aussi rapide que BufferedReader
, car il utilise des expressions régulières pour lire les fichiers texte, ce qui le ralentit par rapport à BufferedReader
. En utilisant BufferedReader
, vous pouvez lire un bloc à partir d'un fichier texte.
BufferedReader bf = new BufferedReader(new FileReader("FileName"));
vous pouvez ensuite utiliser readLine () pour lire depuis bf.
J'espère que cela sert votre but.
vous pouvez utiliser FileChannel et ByteBuffer à partir de Java NIO. La taille de ByteBuffer est la partie la plus critique dans la lecture des données plus rapide que ce que j'ai observé. Le code ci-dessous lira le contenu du fichier.
static public void main( String args[] ) throws Exception
{
FileInputStream fileInputStream = new FileInputStream(
new File("sample4.txt"));
FileChannel fileChannel = fileInputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
fileChannel.read(byteBuffer);
byteBuffer.flip();
int limit = byteBuffer.limit();
while(limit>0)
{
System.out.print((char)byteBuffer.get());
limit--;
}
fileChannel.close();
}
Vous pouvez vérifier '\ n' pour la nouvelle ligne ici. Merci.
Même si vous pouvez disperser et getter moyen de lire les fichiers plus rapidement, i.e.
fileChannel.get(buffers);
où
ByteBuffer b1 = ByteBuffer.allocate(B1);
ByteBuffer b2 = ByteBuffer.allocate(B2);
ByteBuffer b3 = ByteBuffer.allocate(B3);
ByteBuffer[] buffers = {b1, b2, b3};
Cela évite au processus utilisateur d’effectuer plusieurs appels système (ce qui peut être coûteux) et permet au noyau d’optimiser le traitement des données car il contient des informations sur le transfert total. Si plusieurs processeurs sont disponibles, il est même possible de remplir et vider plusieurs mémoires tampons. simultanément.
De this book.
J'ai fait un Gist en comparant différentes méthodes:
import Java.io.*;
import Java.nio.file.Files;
import Java.nio.file.Paths;
import Java.util.ArrayList;
import Java.util.LinkedList;
import Java.util.List;
import Java.util.Scanner;
import Java.util.function.Function;
public class Main {
public static void main(String[] args) {
String path = "resources/testfile.txt";
measureTime("BufferedReader.readLine() into ArrayList", Main::bufferReaderToLinkedList, path);
measureTime("BufferedReader.readLine() into LinkedList", Main::bufferReaderToArrayList, path);
measureTime("Files.readAllLines()", Main::readAllLines, path);
measureTime("Scanner.nextLine() into ArrayList", Main::scannerArrayList, path);
measureTime("Scanner.nextLine() into LinkedList", Main::scannerLinkedList, path);
measureTime("RandomAccessFile.readLine() into ArrayList", Main::randomAccessFileArrayList, path);
measureTime("RandomAccessFile.readLine() into LinkedList", Main::randomAccessFileLinkedList, path);
System.out.println("-----------------------------------------------------------");
}
private static void measureTime(String name, Function<String, List<String>> fn, String path) {
System.out.println("-----------------------------------------------------------");
System.out.println("run: " + name);
long startTime = System.nanoTime();
List<String> l = fn.apply(path);
long estimatedTime = System.nanoTime() - startTime;
System.out.println("lines: " + l.size());
System.out.println("estimatedTime: " + estimatedTime / 1_000_000_000.);
}
private static List<String> bufferReaderToLinkedList(String path) {
return bufferReaderToList(path, new LinkedList<>());
}
private static List<String> bufferReaderToArrayList(String path) {
return bufferReaderToList(path, new ArrayList<>());
}
private static List<String> bufferReaderToList(String path, List<String> list) {
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(
path));
String line = reader.readLine();
while (line != null) {
line = reader.readLine();
list.add(line);
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
private static List<String> readAllLines(String path) {
try {
return Files.readAllLines(Paths.get(path));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private static List<String> randomAccessFileLinkedList(String path) {
return randomAccessFile(path, new LinkedList<>());
}
private static List<String> randomAccessFileArrayList(String path) {
return randomAccessFile(path, new ArrayList<>());
}
private static List<String> randomAccessFile(String path, List<String> list) {
try {
RandomAccessFile file = new RandomAccessFile(path, "r");
String str;
while ((str = file.readLine()) != null) {
list.add(str);
}
file.close();
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
private static List<String> scannerLinkedList(String path) {
return scanner(path, new LinkedList<>());
}
private static List<String> scannerArrayList(String path) {
return scanner(path, new ArrayList<>());
}
private static List<String> scanner(String path, List<String> list) {
try {
Scanner scanner = new Scanner(new File(path));
while (scanner.hasNextLine()) {
list.add(scanner.nextLine());
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return list;
}
}
exécutez: BufferedReader.readLine () dans ArrayList, lignes: 1000000, heure estimée: 0.105118655
exécutez: BufferedReader.readLine () dans LinkedList, lignes: 1000000, Heure estimée: 0.072696934
exécuter: Files.readAllLines (), lignes: 1000000, Heure estimée: 0.087753316
exécutez: Scanner.nextLine () dans ArrayList, lignes: 1000000, heure estimée: 0.743121734
exécutez: Scanner.nextLine () dans LinkedList, lignes: 1000000, Heure estimée: 0.867049885
exécutez: RandomAccessFile.readLine () dans ArrayList, lignes: 1000000, heure estimée: 11.413323046
exécutez: RandomAccessFile.readLine () dans LinkedList, lignes: 1000000, Heure estimée: 11.423862897
BufferedReader
est le plus rapide, Files.readAllLines()
est également acceptable, Scanner
est lent en raison de l’expression régulière, RandomAccessFile
est inacceptable
Utilisez BufferedReader pour un accès aux fichiers hautes performances. Mais la taille de tampon par défaut de 8192 octets est souvent trop petite. Pour les fichiers volumineux, vous pouvez augmenter la taille de la mémoire tampon par ordres de grandeur pour améliorer vos performances de lecture de fichiers. Par exemple:
BufferedReader br = new BufferedReader("file.dat", 1000 * 8192);
while ((thisLine = br.readLine()) != null) {
System.out.println(thisLine);
}
en mettant à jour ce fil, nous avons maintenant Java 8 pour faire le travail
List<String> lines = Files.readAllLines(Paths.get(file_path);
Vous devez rechercher quelle partie du programme prend du temps.
Selon la réponse de EJP, vous devez utiliser BufferedReader.
Si vraiment le traitement des chaînes prend du temps, vous devriez envisager d'utiliser des threads, un thread lira à partir des lignes de fichiers et de files d'attente. Les autres threads du processeur de chaînes vont supprimer les lignes et les traiter. Vous devrez déterminer le nombre de threads à utiliser. Le nombre de threads à utiliser dans l'application doit être associé au nombre de cœurs de la CPU, afin d'utiliser pleinement la CPU.