2012-04-25 5 views
5

Каков правильный способ чтения текстового файла в массив строк? Я нашел следующее на Rosetta Stone:чтение файла в массив строк по d

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

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

    return lines; 
} 

, но похоже, что он делает один массив размер в каждой строке, которая является довольно неэффективным. Я мог бы следить за количеством строк читать и изменять размер массива с помощью стандартного метода удвоения

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; 

но этого достаточно шаблонного кода, что я должен задаться вопросом, если я не только с видом что-то в стандартной библиотеке, уже делает это для меня.


Edit: давая комментарий больше видимость fwend в: this article подробно описывает, как в массив распределителей работ, и почему Добавление данных обрабатывается эффективно исполняющей

ответ

4

На самом деле, D удвоит зарезервированное пространство массива значение всякий раз, когда он заканчивается, поэтому вам не нужно делать это вручную. Существует много информации о массивах D's here

+1

Я прочитал это, и он ничего не сказал о внутренней стратегии изменения размера при добавлении к массиву –

+0

Да, я просто заметил это, но я знаю, что так оно и работает. Для более подробной информации D фактически выделяет память в кусках размера «сила-два», поэтому, если массив растет больше, скажем, 32 байта, он перераспределяется на кусок 64 байта. – ricochet1k

+0

хорошо, спасибо, это хорошо знать –

4

Вы, вероятно, сначала получите много перераспределений, но по мере роста массива его емкость должна расти так, что он с меньшей вероятностью будет выделяться с последующим добавлением. Вы можете распечатать свойство массива capacity, но чтобы узнать, как он растет.

Если вы особенно обеспокоены добавлением производительности, однако, то вы, вероятно, следует использовать std.array.Appender, в этом случае, ваш код будет выглядеть примерно так:

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 разработан, чтобы сделать добавление более эффективным и будет использовать любые трюки, которые он может сделать, чтобы сделать добавление более эффективным, чем ~=.

4

Может быть, это:

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); 
} 

Он должен быть достаточно быстро, так как результат будет просто создание ломтиков входной строки загруженной, а не выделение новых массивов (помимо выделения ломтиков себя, IOW указатель + длина поля).

Смежные вопросы