2012-04-25 39 views
5

Cách thích hợp để đọc một tệp văn bản thành một chuỗi các dòng là gì? Tôi đã tìm thấy thông tin sau trên Rosetta Stone:đọc một tệp thành một dãy các dòng trong d

string[] readLines(string filename) { 
    auto f = File(filename); 
    scope(exit) f.close(); 
    string[] lines; 

    foreach (str; f.byLine) { 
    lines ~= str.idup; 
    } 

    return lines; 
} 

nhưng có vẻ như nó đang thực hiện một thay đổi kích thước mảng trên mỗi dòng, điều này khá không hiệu quả. Tôi có thể theo dõi các số dòng đọc và thay đổi kích thước mảng thông qua phương thức tăng gấp đôi tiêu chuẩn

int i = 0; 
    foreach (str; f.byLine) { 
    if (lines.length <= i + 1) { 
     lines.length = lines.length * 2 + 1; 
    } 
    lines[i] = str.idup; 
    i++; 
    } 
    lines.length = i; 

nhưng đó là đủ mã boilerplate rằng tôi phải tự hỏi, nếu tôi không chỉ nhìn ra một cái gì đó trong thư viện chuẩn đã làm điều này cho tôi.


Edit: cho bình luận dễ thấy hơn fwend của: this article mô tả chi tiết cách thức hoạt động mảng cấp phát, và lý do tại sao phụ thêm được xử lý một cách hiệu quả bởi thời gian chạy

Trả lời

4

Trên thực tế, D sẽ tăng gấp đôi không gian dành riêng của mảng bất cứ khi nào nó chạy ra khỏi phòng, vì vậy bạn không cần phải làm điều đó bằng tay. Có rất nhiều thông tin về các mảng của D here

+1

tôi đọc qua điều đó, và nó không nói bất cứ điều gì về chiến lược thay đổi kích thước nội bộ khi phụ thêm vào một mảng –

+0

Vâng, tôi đã nhận thấy điều đó, nhưng tôi biết đó là cách nó hoạt động. Để biết thêm chi tiết, D thực sự phân bổ bộ nhớ theo khối lượng của hai kích thước, vì vậy nếu mảng phát triển lớn hơn, nói, 32 byte, nó sẽ phân bổ lại thành một đoạn 64 byte. – ricochet1k

+0

okay, cảm ơn, đó là điều tốt để biết –

4

Có thể bạn sẽ nhận được nhiều bản phân phối ban đầu, nhưng khi mảng phát triển, khả năng của nó sẽ tăng lên vì nó ít có khả năng phân bổ hơn nữa. Bạn có thể in ra thuộc tính của capacity của mảng mặc dù để xem nó phát triển như thế nào.

Nếu bạn đặc biệt lo lắng về phụ thêm hiệu suất, tuy nhiên, sau đó bạn nên có lẽ sử dụng std.array.Appender, trong trường hợp này, mã của bạn sẽ giống như thế này:

string[] readLines(string filename) 
{ 
    auto file = File(filename); 
    auto lines = appender!(string[]); 

    foreach(line; file.byLine()) 
     lines.put(to!string(line)); 

    return lines.data; 
} 

Appender được thiết kế để làm cho phụ hiệu quả hơn và sẽ tận dụng lợi thế của bất kỳ thủ đoạn nào có thể để tạo thêm hiệu quả hơn ~= sẽ là của chính nó.

4

Có lẽ đây:

import std.algorithm; 
import std.array; 
import std.file; 

string[] readLines(string input) 
{ 
    Appender!(string[]) result; 
    foreach (line; input.splitter("\n")) 
     result.put(line); 
    return result.data; 
} 

void main() 
{ 
    string input = cast(string)std.file.read("test.d"); 
    string[] lines = readLines(input); 
} 

Nó phải đủ nhanh kể từ khi kết quả là chỉ cần tạo các slices của chuỗi đầu vào được tải sẵn và không phân bổ mảng mới (ngoài việc phân bổ các lát bản thân, IOW con trỏ + chiều dài lĩnh vực).

Các vấn đề liên quan