효율적인 방법으로 파일의 줄 수를 어떻게 얻을 수 있습니까?
큰 파일이 있습니다. 약 3.000-20.000 라인이 포함됩니다. Java를 사용하여 파일의 총 줄 수를 어떻게 얻을 수 있습니까?
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
int lines = 0;
while (reader.readLine() != null) lines++;
reader.close();
업데이트 : 여기에서 제기 된 성능 질문에 답하기 위해 측정했습니다. 첫 번째로, 프로그램을 눈에 띄는 시간 동안 실행하기에는 20.000 줄이 너무 적습니다. 5 백만 줄의 텍스트 파일을 만들었습니다. 이 솔루션 (-server 또는 -XX-options와 같은 매개 변수없이 Java로 시작)은 내 상자에서 약 11 초가 필요했습니다. 와 같은 wc -l
11 초 (UNIX 커맨드 라인 툴 라인을 계산한다). 모든 문자를 읽고 '\ n'을 찾는 솔루션에는 104 초가 필요했습니다.
Files.lines
자바 8 이상은 사용 아주 좋은 짧은 방법이 NIO를 사용하여 Files.lines
.
Path path = Paths.get("./big_file.txt");
long lineCount = Files.lines(path).count();
UTF-8 의 기본 문자 인코딩입니다 . 특정 데이터 파일과 일치 하도록 대체 인코딩 을 지정할 수 있습니다 .
뭔가
public static int countLines(File aFile) throws IOException {
LineNumberReader reader = null;
try {
reader = new LineNumberReader(new FileReader(aFile));
while ((reader.readLine()) != null);
return reader.getLineNumber();
} catch (Exception ex) {
return -1;
} finally {
if(reader != null)
reader.close();
}
}
이에 대한 해결책을 찾았습니다. 유용 할 수 있습니다.
다음은 파일에서 줄 수를 세는 코드 조각입니다.
File file = new File("/mnt/sdcard/abc.txt");
LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(file));
lineNumberReader.skip(Long.MAX_VALUE);
int lines = lineNumberReader.getLineNumber();
lineNumberReader.close();
파일을 읽고 개행 문자의 수를 세십시오. 한 번에 한 줄씩 Java로 파일을 읽는 쉬운 방법은 java.util.Scanner 클래스입니다.
이것은 얻을 수있는 것만 큼 효율적입니다. 버퍼링 된 바이너리 읽기, 문자열 변환 없음,
FileInputStream stream = new FileInputStream("/tmp/test.txt");
byte[] buffer = new byte[8192];
int count = 0;
int n;
while ((n = stream.read(buffer)) > 0) {
for (int i = 0; i < n; i++) {
if (buffer[i] == '\n') count++;
}
}
stream.close();
System.out.println("Number of lines: " + count);
정확한 라인 수 또는 근사치 만 필요합니까? 대용량 파일을 병렬로 처리하고 종종 정확한 줄 수를 알 필요가 없습니다. 그런 다음 샘플링으로 돌아갑니다. 파일을 10 개의 1MB 청크로 분할하고 각 청크에서 행을 계산 한 다음 10을 곱하면 대략적인 행 수를 얻을 수 있습니다.
이전의 모든 답변은 전체 파일을 읽고이 작업을 수행하는 동안 찾은 줄 바꿈의 양을 계산하는 것이 좋습니다. 일부는 "효과적이지 않다"고 언급했지만 그게 유일한 방법입니다. "줄"은 파일 내부의 단순한 문자와는 다릅니다. 그리고 그 문자를 계산하려면 파일 내의 모든 문자를 봐야합니다.
미안하지만 선택의 여지가 없습니다. :-)
이미 게시 된 답변이 충분히 빠르지 않은 경우 특정 문제에 맞는 솔루션을 찾아야 할 것입니다.
예를 들어 이러한 텍스트 파일이 추가 만되는 로그이고 정기적으로 해당 파일의 줄 수를 알아야하는 경우 인덱스를 만들 수 있습니다. 이 색인에는 파일의 행 수, 파일이 마지막으로 수정 된시기 및 파일 크기가 포함됩니다. 이렇게하면 이미 본 모든 줄을 건너 뛰고 새 줄만 읽음으로써 파일의 줄 수를 다시 계산할 수 있습니다.
빠르고 더럽지 만 작업을 수행합니다.
import java.io.*;
public class Counter {
public final static void main(String[] args) throws IOException {
if (args.length > 0) {
File file = new File(args[0]);
System.out.println(countLines(file));
}
}
public final static int countLines(File file) throws IOException {
ProcessBuilder builder = new ProcessBuilder("wc", "-l", file.getAbsolutePath());
Process process = builder.start();
InputStream in = process.getInputStream();
LineNumberReader reader = new LineNumberReader(new InputStreamReader(in));
String line = reader.readLine();
if (line != null) {
return Integer.parseInt(line.trim().split(" ")[0]);
} else {
return -1;
}
}
}
이 솔루션은 1,380 만 줄의 파일에서 테스트했을 때 최고 등급의 답변보다 약 3.6 배 빠릅니다. 단순히 바이트를 버퍼로 읽고 \n
문자를 계산합니다 . 버퍼 크기로 재생할 수는 있지만 내 컴퓨터에서는 8KB 이상의 코드가 코드를 더 빠르게 만들지 못했습니다.
private int countLines(File file) throws IOException {
int lines = 0;
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[BUFFER_SIZE]; // BUFFER_SIZE = 8 * 1024
int read;
while ((read = fis.read(buffer)) != -1) {
for (int i = 0; i < read; i++) {
if (buffer[i] == '\n') lines++;
}
}
fis.close();
return lines;
}
유닉스 "wc"명령을 시도하십시오. 나는 그것을 사용한다는 의미가 아니라 소스를 다운로드하고 그들이 어떻게하는지 확인하십시오. 아마도 c에있을 수 있지만 동작을 java로 쉽게 이식 할 수 있습니다. 자신 만의 문제를 만드는 데있어 문제는 결말 cr / lf 문제를 설명하는 것입니다.
이전 게시물이지만 다음 사람들에게 유용 할 수있는 솔루션이 있습니다. 진행 상황을 알기 위해 파일 길이를 사용하지 않는 이유는 무엇입니까? 물론 줄은 거의 같은 크기 여야하지만 큰 파일에는 매우 잘 작동합니다.
public static void main(String[] args) throws IOException {
File file = new File("yourfilehere");
double fileSize = file.length();
System.out.println("=======> File size = " + fileSize);
InputStream inputStream = new FileInputStream(file);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "iso-8859-1");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
int totalRead = 0;
try {
while (bufferedReader.ready()) {
String line = bufferedReader.readLine();
// LINE PROCESSING HERE
totalRead += line.length() + 1; // we add +1 byte for the newline char.
System.out.println("Progress ===> " + ((totalRead / fileSize) * 100) + " %");
}
} finally {
bufferedReader.close();
}
}
It allows to see the progression without doing any full read on the file. I know it depends on lot of elements, but I hope it will be usefull :).
[Edition] Here is a version with estimated time. I put some SYSO to show progress and estimation. I see that you have a good time estimation errors after you have treated enough line (I try with 10M lines, and after 1% of the treatment, the time estimation was exact at 95%). I know, some values has to be set in variable. This code is quickly written but has be usefull for me. Hope it will be for you too :).
long startProcessLine = System.currentTimeMillis();
int totalRead = 0;
long progressTime = 0;
double percent = 0;
int i = 0;
int j = 0;
int fullEstimation = 0;
try {
while (bufferedReader.ready()) {
String line = bufferedReader.readLine();
totalRead += line.length() + 1;
progressTime = System.currentTimeMillis() - startProcessLine;
percent = (double) totalRead / fileSize * 100;
if ((percent > 1) && i % 10000 == 0) {
int estimation = (int) ((progressTime / percent) * (100 - percent));
fullEstimation += progressTime + estimation;
j++;
System.out.print("Progress ===> " + percent + " %");
System.out.print(" - current progress : " + (progressTime) + " milliseconds");
System.out.print(" - Will be finished in ===> " + estimation + " milliseconds");
System.out.println(" - estimated full time => " + (progressTime + estimation));
}
i++;
}
} finally {
bufferedReader.close();
}
System.out.println("Ended in " + (progressTime) + " seconds");
System.out.println("Estimative average ===> " + (fullEstimation / j));
System.out.println("Difference: " + ((((double) 100 / (double) progressTime)) * (progressTime - (fullEstimation / j))) + "%");
Feel free to improve this code if you think it's a good solution.
Read the file line by line and increment a counter for each line until you have read the entire file.
Probably the fastest solution in pure Java would be to read the file as bytes using a NIO Channel into large ByteBuffer. Then using your knowledge of the file encoding scheme(s) count the encoded CR and/or NL bytes, per the relevant line separator convention.
The keys to maximising throughput will be:
- make sure that you read the file in large chunks,
- avoid copying the bytes from one buffer to another,
- avoid copying / converting bytes into characters, and
- avoid allocating objects to represent the file lines.
The actual code is too complicated for me to write on the fly. Besides, the OP is not asking for the fastest solution.
The buffered reader is overkill
Reader r = new FileReader("f.txt");
int count = 0;
int nextchar = 0;
while (nextchar != -1){
nextchar = r.read();
if (nextchar == Character.getNumericValue('\n') ){
count++;
}
}
My search for a simple example has createde one thats actually quite poor. calling read() repeadedly for a single character is less than optimal. see here for examples and measurements.
'Program Tip' 카테고리의 다른 글
Symfony2 컨트롤러에서 사용자 IP 주소를 어떻게 얻습니까? (0) | 2020.11.09 |
---|---|
ServerName이없는 기본 가상 호스트에서 HTTP를 HTTPS로 리디렉션 (0) | 2020.11.09 |
최대 절전 모드 : flush () 및 commit () (0) | 2020.11.09 |
isset ()에 대한 PHP 속기? (0) | 2020.11.09 |
Xcode 6 및 임베디드 프레임 워크는 iOS8에서만 지원됩니다. (0) | 2020.11.08 |