Thread overview
std.file vs std.stream
Mar 04, 2010
Ludovic A.
Mar 04, 2010
Ludovic A.
Mar 04, 2010
Ali Çehreli
March 04, 2010
I am trying to write a simple file parser in D2. Following examples I found 2 working ways to read a line and print it:

import std.stream
(...)
  Stream file = new BufferedFile(filename);
  foreach(char[] line; file)
  {
    writefln("line: %s",line);
  }

OR

import std.file;
(...)
File* file = new File(filename);
   while (!file.eof())
   {
     writef("%s", file.readln());
   }

My question from there is what is the difference between opening a stream and a file _in this case_, and what is the most appropriate in this case?

Also in the foreach I can not write foreach (string line, file) but I have to use char[]. Is there a way to go around this?

Finally I can not use foreach in the std.file example, because the compiler says "foreach: File* is not an aggregate type". I was surprised that foreach worked on a Stream at the first place, so no big deal :) But what do we have under the hood? How can it work for Stream and not for File? Is the limitation coming from the foreach implementation?
March 04, 2010
Ludovic A. wrote:
> I am trying to write a simple file parser in D2. Following examples I found 2
> working ways to read a line and print it:


Where did you find the examples?  They seem pretty out-of-date.


> import std.stream
> (...)
>   Stream file = new BufferedFile(filename);
>   foreach(char[] line; file)
>   {
>     writefln("line: %s",line);
>   }
> 
> OR
> 
> import std.file;
> (...)
> File* file = new File(filename);
>    while (!file.eof())
>    {
>      writef("%s", file.readln());
>    }
> 
> My question from there is what is the difference between opening a stream and
> a file _in this case_, and what is the most appropriate in this case?


Did you really mean 'import std.file' up there, or did you mean 'import std.stdio' -- because that's where the File type is defined.

What you're seeing here is actually a consequence of Phobos very much being a work-in-progress.  std.stdio was completely rewritten about a year ago, and it most likely contains what you're looking for.

std.stream, on the other hand, hasn't seen major updates since 2005 or so, and is most likely an old left-over from D1.  I suspect it will be removed soon, or at least completely rewritten to adhere to the range interface.


So, my advice is to use std.stdio.File, and to use it like this:

  import std.stdio;
  ...
  auto file = File(filename);
  foreach (line; file.byLine)
  {
      writeln(line);
  }

Two things one should be aware of with the above example:

  1. File is a struct, not a class, which is why I didn't 'new' it.
     However, under the hood it works as a reference type, does its
     own reference counting, and will close the file *immediately*
     when there are no more references to it (i.e. the last copy of
     'file' goes out of scope).

  2. file.byLine returns a range that iterates over the lines of the
     file.  The 'line' variable is a char[] because the buffer is
     reused for each iteration, whereas the string type is immutable.
     Thus, if you want to store the contents of the 'line' array
     somewhere you need to copy it.

The std.stdio docs (with a few examples) can be found here:

  http://www.digitalmars.com/d/2.0/phobos/std_stdio.html


> Also in the foreach I can not write foreach (string line, file) but I have to
> use char[]. Is there a way to go around this?
> 
> Finally I can not use foreach in the std.file example, because the compiler
> says "foreach: File* is not an aggregate type". I was surprised that foreach
> worked on a Stream at the first place, so no big deal :) But what do we have
> under the hood? How can it work for Stream and not for File? Is the limitation
> coming from the foreach implementation?


I'm beginning to suspect you are using an ancient version of DMD2.  Am I right?

-Lars
March 04, 2010
Hej,

thanks! First I want to underline that I use Digital Mars D Compiler v2.040, and my 2 examples are _working_ examples with this compiler. So I really mean that std.file is working on the last D compiler :)

I felt that those examples didn't 'smell' like D, and I also got some import conflicts when I tried to import both std.stream and std.file in the same time. It's clearer now ;)

I am still suprised that I don't have to indicate the type of "line", but I guess it is deduced from whatever file.byLine returns. I will dig out the foreach implementation, sounds pretty cool anyway.

Last but not least, I extensively used the Search function of the Digitalmars website, and I did see information about std.stream / std.file popping on the top results. The Search function also referenced quite a lot of posts in "/archives/" :) I looked at tutorials on dsource, it seems most of them are outdated... Hence my questions: where can I found the last up-to-date D standard well presented like a Javadoc?
March 04, 2010
Lars T. Kyllingstad wrote:

> What you're seeing here is actually a consequence of Phobos very much
> being a work-in-progress.  std.stdio was completely rewritten about a
> year ago, and it most likely contains what you're looking for.
>
> std.stream, on the other hand, hasn't seen major updates since 2005 or
> so, and is most likely an old left-over from D1.  I suspect it will be
> removed soon, or at least completely rewritten to adhere to the range
> interface.

I've been using std.stream.File because it uses the generic Stream interface like dout and din does.

Using std.stream.File should allow cleaner template code without needing 'static if' and other conditional compilation features.

> So, my advice is to use std.stdio.File, and to use it like this:
>
>   import std.stdio;
>   ...
>   auto file = File(filename);
>   foreach (line; file.byLine)
>   {
>       writeln(line);
>   }

std.stdio.File has two advantages that I've discovered so far:

- As you also note, it closes the file immediately. With std.stream.File, I have to use 'scope' objects

- It allows chosing text vs. binary file I/O mode. std.stream.Stream.writefln always converts the newline character according to the system

Ali
March 04, 2010
Ludovic A. wrote:
> Hej,
> 
> thanks! First I want to underline that I use Digital Mars D Compiler v2.040, and
> my 2 examples are _working_ examples with this compiler. So I really mean that
> std.file is working on the last D compiler :)
> 
> I felt that those examples didn't 'smell' like D, and I also got some import
> conflicts when I tried to import both std.stream and std.file in the same time.
> It's clearer now ;)
> 
> I am still suprised that I don't have to indicate the type of "line", but I guess
> it is deduced from whatever file.byLine returns. I will dig out the foreach
> implementation, sounds pretty cool anyway.
> 
> Last but not least, I extensively used the Search function of the Digitalmars
> website, and I did see information about std.stream / std.file popping on the top
> results. The Search function also referenced quite a lot of posts in "/archives/"
> :) I looked at tutorials on dsource, it seems most of them are outdated... Hence
> my questions: where can I found the last up-to-date D standard well presented like
> a Javadoc?

Short answer: You can't. :)

Long answer:
Like I said, Phobos is a work in progress, and now that the language specification itself has been frozen, you can expect big changes to the library in the near future.

The best guide to which parts of Phobos are newest (and therefore less likely to change in the future) is the changelog.  The major changes started with DMD 2.029:

  http://www.digitalmars.com/d/2.0/changelog.html#new2_029

-Lars
March 04, 2010
Ali Çehreli wrote:
> Lars T. Kyllingstad wrote:
> 
>  > What you're seeing here is actually a consequence of Phobos very much
>  > being a work-in-progress.  std.stdio was completely rewritten about a
>  > year ago, and it most likely contains what you're looking for.
>  >
>  > std.stream, on the other hand, hasn't seen major updates since 2005 or
>  > so, and is most likely an old left-over from D1.  I suspect it will be
>  > removed soon, or at least completely rewritten to adhere to the range
>  > interface.
> 
> I've been using std.stream.File because it uses the generic Stream interface like dout and din does.
> 
> Using std.stream.File should allow cleaner template code without needing 'static if' and other conditional compilation features.

Unfortunately it has the major drawback of not working anymore when std.stream is deprecated.

-Lars