Câu trả lời:
Chỉnh sửa muộn màng: Nếu bạn đang sử dụng .NET 4.0 trở lên
Các File
lớp học có một mới ReadLines
phương pháp mà lười biếng liệt kê dòng chứ không phải là tham lam đọc tất cả chúng vào một mảng như ReadAllLines
. Vì vậy, bây giờ bạn có thể có cả hiệu quả và sự đồng nhất với:
var lineCount = File.ReadLines(@"C:\file.txt").Count();
Câu trả lời gốc
Nếu bạn không quá bận tâm về hiệu quả, bạn chỉ cần viết:
var lineCount = File.ReadAllLines(@"C:\file.txt").Length;
Đối với một phương pháp hiệu quả hơn bạn có thể làm:
var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
while (reader.ReadLine() != null)
{
lineCount++;
}
}
Chỉnh sửa: Trả lời các câu hỏi về hiệu quả
Lý do tôi nói thứ hai hiệu quả hơn là liên quan đến việc sử dụng bộ nhớ, không nhất thiết phải là tốc độ. Cái đầu tiên tải toàn bộ nội dung của tệp vào một mảng có nghĩa là nó phải phân bổ ít nhất nhiều bộ nhớ bằng kích thước của tệp. Cái thứ hai chỉ lặp lại một dòng tại một thời điểm để nó không bao giờ phải phân bổ nhiều hơn một bộ nhớ trong một dòng. Điều này không quan trọng đối với các tệp nhỏ, nhưng đối với các tệp lớn hơn thì đó có thể là một vấn đề (nếu bạn thử và tìm số dòng trong tệp 4GB trên hệ thống 32 bit, ví dụ, trong đó đơn giản là không đủ không gian địa chỉ chế độ người dùng để phân bổ một mảng lớn này).
Về tốc độ tôi không mong đợi sẽ có nhiều thứ trong đó. Có thể ReadAllLines có một số tối ưu hóa bên trong, nhưng mặt khác, nó có thể phải phân bổ một khối lớn bộ nhớ. Tôi đoán rằng ReadAllLines có thể nhanh hơn đối với các tệp nhỏ, nhưng chậm hơn đáng kể đối với các tệp lớn; mặc dù cách duy nhất để nói là đo nó bằng Đồng hồ bấm giờ hoặc trình lược tả mã.
ReadLines().Count()
bạn sẽ cần thêm một phần using System.Linq
bao gồm. Có vẻ như không trực quan để yêu cầu bổ sung, vì vậy đó là lý do tại sao tôi đề cập đến nó. Nếu bạn đang sử dụng Visual Studio, có thể phần bổ sung này được thực hiện tự động cho bạn.
Nếu dễ dàng, bạn có nghĩa là một dòng mã dễ giải mã nhưng cơ hội không hiệu quả?
string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();
Đó có lẽ là cách nhanh nhất để biết có bao nhiêu dòng.
Bạn cũng có thể làm (tùy thuộc vào việc bạn có đệm nó không)
#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}
Có rất nhiều cách khác nhưng một trong những cách trên có lẽ là những gì bạn sẽ đi với.
Bạn có thể nhanh chóng đọc nó và tăng bộ đếm, chỉ cần sử dụng vòng lặp để tăng, không làm gì với văn bản.
Việc đọc một tệp trong chính nó mất một thời gian, rác thu thập kết quả là một vấn đề khác khi bạn đọc toàn bộ tệp chỉ để đếm (các) ký tự dòng mới,
Tại một số điểm, ai đó sẽ phải đọc các ký tự trong tệp, bất kể đây là khung hoặc nếu đó là mã của bạn. Điều này có nghĩa là bạn phải mở tệp và đọc nó vào bộ nhớ nếu tệp lớn, điều này sẽ có khả năng là một vấn đề vì bộ nhớ cần phải được thu gom rác.
Nima Ara đã thực hiện một phân tích hay mà bạn có thể cân nhắc
Đây là giải pháp được đề xuất, vì nó đọc 4 ký tự cùng một lúc, đếm ký tự nguồn cấp dữ liệu và sử dụng lại cùng một địa chỉ bộ nhớ để so sánh ký tự tiếp theo.
private const char CR = '\r';
private const char LF = '\n';
private const char NULL = (char)0;
public static long CountLinesMaybe(Stream stream)
{
Ensure.NotNull(stream, nameof(stream));
var lineCount = 0L;
var byteBuffer = new byte[1024 * 1024];
const int BytesAtTheTime = 4;
var detectedEOL = NULL;
var currentChar = NULL;
int bytesRead;
while ((bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
var i = 0;
for (; i <= bytesRead - BytesAtTheTime; i += BytesAtTheTime)
{
currentChar = (char)byteBuffer[i];
if (detectedEOL != NULL)
{
if (currentChar == detectedEOL) { lineCount++; }
currentChar = (char)byteBuffer[i + 1];
if (currentChar == detectedEOL) { lineCount++; }
currentChar = (char)byteBuffer[i + 2];
if (currentChar == detectedEOL) { lineCount++; }
currentChar = (char)byteBuffer[i + 3];
if (currentChar == detectedEOL) { lineCount++; }
}
else
{
if (currentChar == LF || currentChar == CR)
{
detectedEOL = currentChar;
lineCount++;
}
i -= BytesAtTheTime - 1;
}
}
for (; i < bytesRead; i++)
{
currentChar = (char)byteBuffer[i];
if (detectedEOL != NULL)
{
if (currentChar == detectedEOL) { lineCount++; }
}
else
{
if (currentChar == LF || currentChar == CR)
{
detectedEOL = currentChar;
lineCount++;
}
}
}
}
if (currentChar != LF && currentChar != CR && currentChar != NULL)
{
lineCount++;
}
return lineCount;
}
Ở trên, bạn có thể thấy rằng một dòng được đọc một ký tự cùng một lúc bởi khung bên dưới khi bạn cần đọc tất cả các ký tự để xem nguồn cấp dữ liệu.
Nếu bạn mô tả nó như đã thực hiện thì Nima bạn sẽ thấy rằng đây là một cách khá nhanh và hiệu quả để làm việc này.
Một tùy chọn khả thi, và một tùy chọn mà tôi đã sử dụng cá nhân, sẽ là thêm tiêu đề của riêng bạn vào dòng đầu tiên của tệp. Tôi đã làm điều này cho một định dạng mô hình tùy chỉnh cho trò chơi của tôi. Về cơ bản, tôi có một công cụ tối ưu hóa các tệp .obj của mình, loại bỏ những thứ nhảm nhí mà tôi không cần, chuyển đổi chúng thành một bố cục tốt hơn và sau đó ghi tổng số đường, mặt, chuẩn, đỉnh và UV kết cấu trên dòng đầu tiên Dữ liệu đó sau đó được sử dụng bởi các bộ đệm mảng khác nhau khi mô hình được tải.
Điều này cũng hữu ích vì bạn chỉ cần lặp qua tệp một lần để tải nó vào, thay vì một lần để đếm các dòng và một lần nữa để đọc dữ liệu vào bộ đệm đã tạo của bạn.
try {
string path = args[0];
FileStream fh = new FileStream(path, FileMode.Open, FileAccess.Read);
int i;
string s = "";
while ((i = fh.ReadByte()) != -1)
s = s + (char)i;
//its for reading number of paragraphs
int count = 0;
for (int j = 0; j < s.Length - 1; j++) {
if (s.Substring(j, 1) == "\n")
count++;
}
Console.WriteLine("The total searches were :" + count);
fh.Close();
} catch(Exception ex) {
Console.WriteLine(ex.Message);
}
Bạn có thể khởi chạy tệp thực thi " wc .exe" (đi kèm với UnixUtils và không cần cài đặt) chạy như một quy trình bên ngoài. Nó hỗ trợ các phương thức đếm dòng khác nhau (như unix vs mac vs windows).