Tôi có một tệp lớn. Nó bao gồm khoảng 3.000-20.000 dòng. Làm thế nào tôi có thể nhận được tổng số dòng trong tệp bằng cách sử dụng Java?Làm cách nào để có thể đếm số lượng dòng trong một tệp theo cách hiệu quả?
Trả lời
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
int lines = 0;
while (reader.readLine() != null) lines++;
reader.close();
Cập nhật: Để trả lời các câu hỏi hiệu suất lớn lên ở đây, tôi đã thực hiện một phép đo. Điều đầu tiên: 20.000 dòng là quá ít, để có được chương trình chạy trong một thời gian đáng chú ý. Tôi đã tạo một tệp văn bản với 5 triệu dòng. Giải pháp này (bắt đầu bằng java mà không có tham số như -server hoặc -XX-options) cần khoảng 11 giây trên hộp của tôi. Tương tự với wc -l
(UNIX dòng lệnh-công cụ để đếm dòng), 11 giây. Giải pháp đọc từng ký tự đơn và tìm kiếm '\ n' cần 104 giây, gấp 9-10 lần.
Bạn có ý nghĩa gì? Hiệu suất? Trong trường hợp đó bạn sẽ không có cách nào tốt hơn, bởi vì các dòng có thể có độ dài khác nhau, bạn sẽ phải đọc toàn bộ tệp, để đếm số dòng (wc cũng vậy). Nếu bạn nói về hiệu quả lập trình hơn tôi chắc chắn bạn có thể đặt nó trong một phương pháp tiện ích (hoặc một số thư viện phổ biến đã làm nó đã). – Mnementh
@Firstthumb. Không hiệu quả, nhưng ai quan tâm. Anh ta chỉ đếm 20k dòng mà là khá nhỏ. Mã này nhận được phiếu bầu của tôi là đơn giản nhất. –
hiệu suất của LineNumberReader vì nó mở rộng BufferedReader như thế nào? – Narayan
Đọc tệp thông qua và đếm số ký tự dòng mới. Một cách dễ dàng để đọc một tệp trong Java, một dòng tại một thời điểm, là lớp java.util.Scanner.
Đọc dòng tệp theo dòng và tăng bộ đếm cho mỗi dòng cho đến khi bạn đọc toàn bộ tệp.
sử dụng LineNumberReader
cái gì đó như
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();
}
}
Người đọc đệm là 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++;
}
}
tìm kiếm của tôi cho một ví dụ đơn giản đã createde một thats thực sự khá nghèo. gọi đọc() repeadedly cho một nhân vật duy nhất là ít hơn tối ưu. xem here để biết các ví dụ và số đo.
BufferedReader xử lý các dòng kết thúc khác nhau. Giải pháp của bạn bỏ qua các kết thúc dòng Mac ('\ r'). Điều đó có thể được. Dù sao, giải pháp của bạn không thực sự đọc từ tệp trong thời điểm này. Tôi nghĩ rằng bạn quên một dòng. – Mnementh
Điều gì sẽ thay đổi nextchar ở đây? Nếu bạn định gọi read() trên mỗi lần lặp lại, tôi mạnh mẽ nghi ngờ rằng phương pháp BufferedReader sẽ * nhanh hơn nhiều * ... –
đó là ý tưởng; -/Tôi muốn viết ví dụ đơn giản nhất có thể. Tôi tự hỏi sự khác biệt về tốc độ sẽ là gì? – NSherwin
Tất cả các câu trả lời trước đây được đề xuất để đọc mặc dù toàn bộ tệp và đếm số lượng dòng mới bạn tìm thấy khi thực hiện việc này. Bạn nhận xét một số là "không hiệu quả" nhưng đó là cách duy nhất bạn có thể làm điều đó. Một "dòng" là không có gì khác như một nhân vật đơn giản bên trong tập tin. Và để đếm nhân vật đó, bạn phải xem xét từng ký tự đơn trong tệp.
Tôi xin lỗi, nhưng bạn không có lựa chọn nào khác. :-)
Nếu câu trả lời đã đăng không đủ nhanh, có thể bạn sẽ phải tìm giải pháp cụ thể cho vấn đề cụ thể của mình.
Ví dụ: nếu các tệp văn bản này là nhật ký chỉ được nối vào và bạn thường xuyên cần biết số dòng trong đó bạn có thể tạo chỉ mục. Chỉ mục này sẽ chứa số dòng trong tệp, khi tệp được sửa đổi lần cuối và tệp lớn như thế nào. Điều này sẽ cho phép bạn tính toán lại số dòng trong tệp bằng cách bỏ qua tất cả các dòng bạn đã thấy và chỉ đọc các dòng mới.
+1 đây có thể là một thuật toán trực tuyến phù hợp. – zeroin23
Có lẽ giải pháp nhanh nhất trong Java thuần túy là đọc tệp dưới dạng byte bằng cách sử dụng Kênh NIO thành ByteBuffer lớn. Sau đó, sử dụng kiến thức của bạn về (các) lược đồ mã hóa tệp đếm số CR và/hoặc byte được mã hóa theo quy ước phân tách đường có liên quan.
Chìa khóa để tối đa hóa thông lượng sẽ là:
- chắc chắn rằng bạn đọc các tập tin trong khối lớn,
- tránh sao chép các byte từ một bộ đệm khác,
- tránh sao chép/chuyển đổi byte thành các ký tự và
- tránh phân bổ các đối tượng để đại diện cho các dòng tệp.
Mã thực tế quá phức tạp để tôi viết khi đang di chuyển. Bên cạnh đó, OP không yêu cầu giải pháp nhanh nhất.
Hãy thử lệnh "wc" unix. Tôi không có nghĩa là sử dụng nó, tôi có nghĩa là tải về các nguồn và xem cách họ làm điều đó. Nó có thể trong c, nhưng bạn có thể dễ dàng chuyển đổi hành vi này sang java. Vấn đề của riêng bạn là giải thích vấn đề cr/lf kết thúc.
này nói về hiệu quả như nó có thể nhận được, đệm đọc nhị phân, không có chuyển đổi chuỗi,
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);
Nhanh chóng và bẩn, nhưng nó không được công việc:
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;
}
}
}
Một hiệu ứng phụ, giải pháp này không phải là nền tảng chéo. – Stephan
Tôi tìm thấy một số giải pháp cho điều này, nó có thể hữu ích cho bạn
Dưới đây là đoạn mã cho, đếm các dòng no.of từ tệp.
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();
kết quả là các dòng 'đếm - 1' – MariuszS
thực tế kết quả là' dòng + 1' –
kết quả là getLineNumber() cộng 1 vì chỉ số dòng bắt đầu tại 0 –
Bạn có cần số dòng chính xác hoặc chỉ xấp xỉ của nó không? Tôi tình cờ xử lý các tệp lớn song song và thường tôi không cần phải biết số lượng dòng chính xác - tôi sau đó hoàn nguyên về lấy mẫu. Tách tệp thành mười khối 1MB và đếm các dòng trong mỗi đoạn, sau đó nhân nó với 10 và bạn sẽ nhận được xấp xỉ khá tốt về số lượng dòng.
Giải pháp này nhanh hơn khoảng 3,6 × so với câu trả lời được đánh giá cao nhất khi được kiểm tra trên một tệp có 13,8 triệu dòng. Nó chỉ đơn giản là đọc các byte vào một bộ đệm và đếm các ký tự \n
. Bạn có thể chơi với kích thước bộ đệm, nhưng trên máy tính của tôi, bất cứ điều gì trên 8KB đã không làm cho mã nhanh hơn.
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;
}
Tôi tự hỏi, nếu sử dụng mẫu RegEx được biên dịch trước sẽ làm cho nó nhanh hơn hoặc chậm hơn.Những gì nó sẽ làm là làm việc với tất cả các kết thúc dòng, tôi tin. Và, tôi nghĩ rằng nó có thể làm cho nó nhanh hơn, quá. – ingyhere
Một số giải pháp trên có thể tận dụng khả năng đệm, nếu lợi ích sẽ giúp ích. Ví dụ, "mới LineNumberReader (mới FileReader (theFilePathStr), 8096)" hoặc một cái gì đó. – ingyhere
Hãy cẩn thận về mã hóa ký tự ... –
Bài đăng cũ, nhưng tôi có giải pháp hữu ích cho người tiếp theo. Tại sao không chỉ sử dụng độ dài tệp để biết tiến trình là gì? Tất nhiên, các dòng phải có kích thước gần như giống nhau, nhưng nó hoạt động rất tốt đối với các tệp lớn:
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();
}
}
Nó cho phép xem tiến trình mà không đọc đầy đủ tệp. Tôi biết nó phụ thuộc vào rất nhiều yếu tố, nhưng tôi hy vọng nó sẽ hữu ích :).
[Ấn bản] Đây là phiên bản có thời gian ước tính. Tôi đặt một số SYSO để hiển thị tiến độ và ước tính. Tôi thấy rằng bạn có một lỗi ước tính thời gian tốt sau khi bạn đã xử lý đủ dòng (tôi thử với 10M dòng và sau 1% điều trị, ước tính thời gian chính xác là 95%). Tôi biết, một số giá trị phải được đặt trong biến. Mã này được viết nhanh nhưng có ích cho tôi. Hy vọng nó sẽ cho bạn quá :).
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))) + "%");
Hãy cải thiện mã này nếu bạn nghĩ đó là giải pháp tốt.
Trong thử nghiệm của tôi, các câu trả lời khác mất ~ 150-300ms trên tệp dòng 118.5k. Sau đây cần 1ms nhưng chỉ gần đúng (báo cáo 117k dòng) và phụ thuộc vào mỗi dòng có kích thước tương tự.
private static void countSize(File file) {
long fileLength = file.length();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
//Skip header as it is of different size
reader.readLine();
String text = reader.readLine();
int lineLength = text.length();
long lines = fileLength/lineLength;
System.out.println(lines);
} catch(IOException e) {
e.printStackTrace();
} finally {
if(reader != null) {
try {
reader.close();
} catch(IOException e) {
//no-op
}
}
}
}
Java 8 + có một cách rất tốt đẹp và ngắn sử dụng nio:
Path path = Paths.get("./big_file.txt");
long lineCount = Files.lines(path).count();
giải pháp giường. chúng tôi có thể gặp sự cố với bộ ký tự – Mikhail
bộ ký tự là UTF-8 theo mặc định –
- 1. cách hiệu quả để đếm các dòng lượng tuân theo một số điều kiện
- 2. Có cách hiệu quả để đếm số lượng giao lộ trong một tập hợp các đoạn đường nhất định không?
- 3. Làm cách nào tôi có thể truy xuất hiệu quả số lượng tệp trong một thư mục?
- 4. Làm thế nào để bạn đếm số lượng thẻ dữ liệu rất lớn một cách hiệu quả bằng Python?
- 5. Làm cách nào để đếm số lần chạy theo chuỗi?
- 6. Làm cách nào để đếm số lượng kết quả trùng khớp bằng một regex?
- 7. Làm cách nào để đếm số lượng JsObject trong JsValue?
- 8. Làm thế nào để đếm số lượng chữ cái trong một chuỗi không có dấu cách?
- 9. Làm cách nào để đếm số lần xuất hiện của giá trị cột một cách hiệu quả trong SQL?
- 10. Làm cách nào để giới hạn số lượng kết quả theo một cột cụ thể trong postgreSQL?
- 11. Làm thế nào tôi có thể đọc một cách hiệu quả FIrst Vài dòng của nhiều tệp trong Delphi
- 12. Có cách nào để đếm số lượng khóa mà một mảng có trong Php?
- 13. Làm cách nào để thay thế một dòng cụ thể theo số dòng trong tệp văn bản?
- 14. Cách hiệu quả để đếm số lượng hoán đổi để chèn sắp xếp một dãy số nguyên theo thứ tự tăng dần
- 15. Làm cách nào để đếm số lượng truy vấn SQL hibernate có trong một yêu cầu Grails?
- 16. Android - Làm thế nào để bạn tải một cách hiệu quả một lượng lớn văn bản trong một TextView?
- 17. Làm cách nào tôi có thể định vị một loại cụ thể trong một Assembly * một cách hiệu quả *?
- 18. Làm thế nào để xóa tài liệu theo truy vấn một cách hiệu quả trong mongo?
- 19. Làm cách nào để hiệu quả trước khi chuyển một dòng sang một tệp lớn trong Powershell
- 20. đếm số dòng trong tệp - Scala
- 21. Cách đếm các dòng của một tệp trong C++?
- 22. Làm cách nào để đếm số lượng hộp kiểm được chọn trên một trang với jQuery
- 23. Theo dõi GPS hiệu quả năng lượng
- 24. Tôi làm cách nào để có được số lượng trang trong một tệp PDF trong Perl?
- 25. Có cách nào tốt hơn để đếm các dòng trong một tệp văn bản không?
- 26. Đếm số lượng tệp trong một thư mục qua javascript
- 27. Làm thế nào để đếm số lượng các dòng thay đổi hoặc thêm vào trong một chi nhánh SVN?
- 28. Cách hiệu quả hơn để đếm giao lộ?
- 29. Làm cách nào để phân tích cú pháp tệp CSV trong Perl hiệu quả?
- 30. Cách thức hiệu quả của dữ liệu lõi cacao để đếm các thực thể
Đánh giá từ bình luận của bạn cho câu trả lời, từ mà bạn đang tìm kiếm là 'hiệu quả', không 'hiệu quả' . – AakashM
Có, Bạn đang ở bên phải – firstthumb
@Đầu tiên: Vui lòng không xóa nhận xét * sau * mọi người đã trả lời họ. Nó làm cho các chủ đề gây nhầm lẫn cho những người đến trễ để hiển thị. – Telemachus