Java kullanarak satır başına yaklaşık 5-6 GB büyük bir metin dosyasını okumak gerekiyor.
Bunu nasıl hızlı bir şekilde yapabilirim?
Java kullanarak satır başına yaklaşık 5-6 GB büyük bir metin dosyasını okumak gerekiyor.
Bunu nasıl hızlı bir şekilde yapabilirim?
Yanıtlar:
Ortak bir desen kullanmaktır
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
}
Karakter kodlaması olmadığını varsayarak verileri daha hızlı okuyabilirsiniz. örneğin ASCII-7 ama çok fazla fark yaratmayacak. Verilerle yaptıklarınızın çok daha uzun sürmesi muhtemeldir.
DÜZENLEME: line
Sızıntı kapsamını önleyen daha az kullanılan bir model .
try(BufferedReader br = new BufferedReader(new FileReader(file))) {
for(String line; (line = br.readLine()) != null; ) {
// process the line.
}
// line is not visible here.
}
GÜNCELLEME: Java 8'de şunları yapabilirsiniz:
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
NOT: #close yönteminin çağrıldığından emin olmak için Stream'i bir try-with block bloğuna yerleştirmeniz gerekir, aksi takdirde GC daha sonra yapana kadar alttaki dosya tanıtıcısı asla kapatılmaz.
for(String line = br.readLine(); line != null; line = br.readLine())
Btw olmasın , Java 8'de bunu yapabilirsiniz try( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
Nefret etmemek zor.
Bu bloga bakın:
Arabellek boyutu belirtilebilir veya varsayılan boyut kullanılabilir. Varsayılan, çoğu amaç için yeterince büyüktür.
// Open the file
FileInputStream fstream = new FileInputStream("textfile.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
System.out.println (strLine);
}
//Close the input stream
fstream.close();
DataInputStream
ve yanlış akış kapalı. Java Tutorial ile yanlış bir şey yok ve böyle üçüncü taraf İnternet çöplerini belirtmeye gerek yok.
Java 8 çıktıktan sonra (Mart 2014) akışları kullanabilirsiniz:
try (Stream<String> lines = Files.lines(Paths.get(filename), Charset.defaultCharset())) {
lines.forEachOrdered(line -> process(line));
}
Dosyadaki tüm satırları yazdırma:
try (Stream<String> lines = Files.lines(file, Charset.defaultCharset())) {
lines.forEachOrdered(System.out::println);
}
StandardCharsets.UTF_8
, Stream<String>
kısalık için kullanın forEach()
ve özellikle forEachOrdered()
bir sebep olmadığı sürece kullanmaktan kaçının .
forEach(this::process)
, ama içeride lambdas olarak kod blokları yazarsanız çirkinleşir forEach()
.
forEachOrdered
sırayla yürütmek için ihtiyacın var . Bu durumda akışı paralel hale getiremeyeceğinizi unutmayın, ancak dosyada binlerce satır olmadığı sürece paralelleştirmenin açılmadığını fark ettim.
Java 7 öncesi için tam hata işleme ve karakter kümesi özelliklerini destekleyen bir örnek. Java 7 ile kodu daha temiz hale getiren, kaynaklarla dene sözdizimini kullanabilirsiniz.
Yalnızca varsayılan karakter kümesini istiyorsanız, InputStream'i atlayabilir ve FileReader'ı kullanabilirsiniz.
InputStream ins = null; // raw byte-stream
Reader r = null; // cooked reader
BufferedReader br = null; // buffered for readLine()
try {
String s;
ins = new FileInputStream("textfile.txt");
r = new InputStreamReader(ins, "UTF-8"); // leave charset out for default
br = new BufferedReader(r);
while ((s = br.readLine()) != null) {
System.out.println(s);
}
}
catch (Exception e)
{
System.err.println(e.getMessage()); // handle exception
}
finally {
if (br != null) { try { br.close(); } catch(Throwable t) { /* ensure close happens */ } }
if (r != null) { try { r.close(); } catch(Throwable t) { /* ensure close happens */ } }
if (ins != null) { try { ins.close(); } catch(Throwable t) { /* ensure close happens */ } }
}
İşte tam hata işleme ile Groovy sürümü:
File f = new File("textfile.txt");
f.withReader("UTF-8") { br ->
br.eachLine { line ->
println line;
}
}
ByteArrayInputStream
bir dize ile beslenen büyük bir metin dosyası okunurken ilgisi var literal?
Java 8'de şunları yapabilirsiniz:
try (Stream<String> lines = Files.lines (file, StandardCharsets.UTF_8))
{
for (String line : (Iterable<String>) lines::iterator)
{
;
}
}
Bazı notlar: Tarafından döndürülen akışın Files.lines
(çoğu akıştan farklı olarak) kapatılması gerekiyor. Burada belirtilen nedenlerden dolayı kullanmaktan kaçınırım forEach()
. Garip kod (Iterable<String>) lines::iterator
bir akışı yinelenebilir bir şekilde yayınlar.
Iterable
Bu kodun uygulanmaması faydalı olmasına rağmen kesinlikle çirkin . (Iterable<String>)
Çalışmak için bir oyuncuya (yani ) ihtiyacı var .
for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
özellikleri kullanmak istemiyorsanız , Files.newBufferedReader
bunun yerine gibi yapılar kullanmak yerine kadar Files.lines
tekrar tekrar kullanmak çok daha basit gibi görünüyor…readLine()
null
(Iterable<String>) lines::iterator
Yapabileceğiniz şey Tarayıcı'yı kullanarak metnin tamamını taramak ve metni satır satır ilerletmektir. Elbette aşağıdakileri içe aktarmalısınız:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public static void readText throws FileNotFoundException {
Scanner scan = new Scanner(new File("samplefilename.txt"));
while(scan.hasNextLine()){
String line = scan.nextLine();
//Here you can manipulate the string the way you want
}
}
Tarayıcı temel olarak tüm metni tarar. While döngüsü metnin tamamında gezinmek için kullanılır.
.hasNextLine()
Fonksiyon metinde daha da çizgiler vardır true döndüren bir boolean. Bu .nextLine()
işlev, daha sonra istediğiniz şekilde kullanabileceğiniz bir Dize olarak tüm bir satırı verir. System.out.println(line)
Metni yazdırmayı deneyin .
Yan Not: .txt dosya türü metnidir.
BufferedReader.readLine()
ve en iyi performansı gösteren yöntemi istedi.
FileReader kodlamayı belirtmenize izin vermez, InputStreamReader
bunun yerine belirtmeniz gerekiyorsa kullanın:
try {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath), "Cp1252"));
String line;
while ((line = br.readLine()) != null) {
// process the line.
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
Bu dosyayı Windows'tan içe aktardıysanız, ANSI kodlaması (Cp1252) olabilir, bu nedenle kodlamayı belirtmeniz gerekir.
Java'da bir dosyayı okumak için 10 farklı yolu belgeledim ve test ettim ve daha sonra bunları 1KB'den 1GB'a kadar test dosyalarında okuyarak birbirlerine karşı çalıştırdım. İşte 1GB test dosyasını okumak için en hızlı 3 dosya okuma yöntemi.
Performans testlerini çalıştırırken konsola hiçbir şey vermediğimden, testi gerçekten yavaşlatacağını unutmayın. Sadece ham okuma hızını test etmek istedim.
1) java.nio.file.Files.readAllBytes ()
Java 7, 8, 9'da test edildi. Bu genel olarak en hızlı yöntemdi. 1 GB'lık bir dosyayı okumak sürekli olarak 1 saniyenin biraz altındaydı.
import java.io..File;
import java.io.IOException;
import java.nio.file.Files;
public class ReadFile_Files_ReadAllBytes {
public static void main(String [] pArgs) throws IOException {
String fileName = "c:\\temp\\sample-1GB.txt";
File file = new File(fileName);
byte [] fileBytes = Files.readAllBytes(file.toPath());
char singleChar;
for(byte b : fileBytes) {
singleChar = (char) b;
System.out.print(singleChar);
}
}
}
2) java.nio.file.Files.lines ()
Bu Java 8 ve 9'da başarıyla test edildi, ancak lambda ifadeleri için destek eksikliği nedeniyle Java 7'de çalışmaz. 1GB'lık bir dosyada okumak, daha büyük dosyaları okumak kadar ikinci sırada yer almak yaklaşık 3,5 saniye sürdü.
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.stream.Stream;
public class ReadFile_Files_Lines {
public static void main(String[] pArgs) throws IOException {
String fileName = "c:\\temp\\sample-1GB.txt";
File file = new File(fileName);
try (Stream linesStream = Files.lines(file.toPath())) {
linesStream.forEach(line -> {
System.out.println(line);
});
}
}
}
3) Arabellek Okuyucu
Java 7, 8, 9'da çalıştığı test edilmiştir. Bu, 1GB test dosyasında okunması yaklaşık 4.5 saniye sürdü.
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class ReadFile_BufferedReader_ReadLine {
public static void main(String [] args) throws IOException {
String fileName = "c:\\temp\\sample-1GB.txt";
FileReader fileReader = new FileReader(fileName);
try (BufferedReader bufferedReader = new BufferedReader(fileReader)) {
String line;
while((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
}
Tüm 10 dosya okuma yöntemi için sıralamaların tamamını burada bulabilirsiniz .
System.out.print/println()
Burada çoğunlukla zamanlama yapıyorsunuz ; ayrıca dosyanın ilk iki durumda belleğe sığacağını varsayıyorsunuz.
Java 7'de:
String folderPath = "C:/folderOfMyFile";
Path path = Paths.get(folderPath, "myFileName.csv"); //or any text file eg.: txt, bat, etc
Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(path , charset)) {
while ((line = reader.readLine()) != null ) {
//separate all csv fields into string array
String[] lineVariables = line.split(",");
}
} catch (IOException e) {
System.err.println(e);
}
StandardCharsets.UTF_8
İşaretli istisnayı önlemek için kullanınCharset.forName("UTF-8")
Java 8'de, kullanmanın bir alternatifi de vardır Files.lines()
. Giriş kaynağı bir dosya ama gibi daha soyut bir şey değilse Reader
ya da InputStream
yapabilirsiniz akışı yoluyla çizgiler BufferedReader
s lines()
yöntemiyle.
Örneğin:
try (BufferedReader reader = new BufferedReader(...)) {
reader.lines().forEach(line -> processLine(line));
}
processLine()
tarafından okunan her bir giriş satırını arayacaktır BufferedReader
.
İçin bir dosya okuma Java ile 8
package com.java.java8;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;
/**
* The Class ReadLargeFile.
*
* @author Ankit Sood Apr 20, 2017
*/
public class ReadLargeFile {
/**
* The main method.
*
* @param args
* the arguments
*/
public static void main(String[] args) {
try {
Stream<String> stream = Files.lines(Paths.get("C:\\Users\\System\\Desktop\\demoData.txt"));
stream.forEach(System.out::println);
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Tarayıcı sınıfını kullanabilirsiniz
Scanner sc=new Scanner(file);
sc.nextLine();
Scanner
iyidir, ancak bu cevap düzgün kullanmak için tam kodu içermez.
BufferedReader.readLine()
kesinlikle birkaç kat daha hızlıdır. Aksini düşünüyorsanız lütfen nedenlerinizi belirtin.
İçindeki readLine()
yöntemi kullanmanız gerekir class BufferedReader
. Bu sınıftan yeni bir nesne oluşturun ve bu yöntemi onun üzerinde çalıştırın ve bir dizeye kaydedin.
Bunu başarmanın açık yolu,
Örneğin:
Eğer varsa dataFile.txt
mevcut dizinde
import java.io.*;
import java.util.Scanner;
import java.io.FileNotFoundException;
public class readByLine
{
public readByLine() throws FileNotFoundException
{
Scanner linReader = new Scanner(new File("dataFile.txt"));
while (linReader.hasNext())
{
String line = linReader.nextLine();
System.out.println(line);
}
linReader.close();
}
public static void main(String args[]) throws FileNotFoundException
{
new readByLine();
}
}
try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
stream.forEach(System.out::println);
}
System.getProperty("os.name").equals("Linux")
==
!
BufferedReader br;
FileInputStream fin;
try {
fin = new FileInputStream(fileName);
br = new BufferedReader(new InputStreamReader(fin));
/*Path pathToFile = Paths.get(fileName);
br = Files.newBufferedReader(pathToFile,StandardCharsets.US_ASCII);*/
String line = br.readLine();
while (line != null) {
String[] attributes = line.split(",");
Movie movie = createMovie(attributes);
movies.add(movie);
line = br.readLine();
}
fin.close();
br.close();
} catch (FileNotFoundException e) {
System.out.println("Your Message");
} catch (IOException e) {
System.out.println("Your Message");
}
Benim için çalışıyor. Umarım size de yardımcı olacaktır.
Daha kesin olarak yapmak için akışları kullanabilirsiniz:
Files.lines(Paths.get("input.txt")).forEach(s -> stringBuffer.append(s);
Genellikle okuma rutinini doğrudan yaparım:
void readResource(InputStream source) throws IOException {
BufferedReader stream = null;
try {
stream = new BufferedReader(new InputStreamReader(source));
while (true) {
String line = stream.readLine();
if(line == null) {
break;
}
//process line
System.out.println(line)
}
} finally {
closeQuiet(stream);
}
}
static void closeQuiet(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (IOException ignore) {
}
}
}
Bu kodu kullanabilirsiniz:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class ReadTextFile {
public static void main(String[] args) throws IOException {
try {
File f = new File("src/com/data.txt");
BufferedReader b = new BufferedReader(new FileReader(f));
String readLine = "";
System.out.println("Reading file using Buffered Reader");
while ((readLine = b.readLine()) != null) {
System.out.println(readLine);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Org.apache.commons.io paketini kullanarak , özellikle Java 6 ve daha eski sürümleri kullanan eski kodlarda daha fazla performans verdi.
Java 7, daha az istisna işleme ve daha kullanışlı yöntemlerle daha iyi bir API'ya sahiptir:
LineIterator lineIterator = null;
try {
lineIterator = FileUtils.lineIterator(new File("/home/username/m.log"), "windows-1256"); // The second parameter is optionnal
while (lineIterator.hasNext()) {
String currentLine = lineIterator.next();
// Some operation
}
}
finally {
LineIterator.closeQuietly(lineIterator);
}
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
Apache Commons IO'yu da kullanabilirsiniz :
File file = new File("/home/user/file.txt");
try {
List<String> lines = FileUtils.readLines(file);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
FileUtils.readLines(file)
kullanımdan kaldırılmış bir yöntemdir. Ayrıca, IOUtils.readLines
bir BufferedReader ve ArrayList kullanan yöntem çağrılır . Bu satır satır değil ve kesinlikle birkaç GB okumak için pratik olacak bir yöntem değildir.