Read file to array of strings in d

What is the correct way to read a text file into an array of strings? I found the following on Rosetta Stone:

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

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

  return lines;
}

but it looks like it makes one array size per line, which is pretty inefficient. I could track the number of rows read and resized by using the standard doubling method

  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;

but this is enough template code, which I have to wonder if I don’t notice something in the standard library that is already doing this for me.


Edit: giving fwend comment more visibility: this article details how the array allocator works and why adding is handled efficiently by the runtime

+5
source share
3

, D , , . D

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

It should be fast enough, because the result simply creates slices of the preloaded input string and does not allocate new arrays (except for the distribution of the slices themselves, IOW pointer fields + lengths).

+4
source

All Articles