www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Strange behavior of read file

reply "Paul Jurczak" <pauljurczak yahoo.com> writes:
module main;

import std.stdio, std.file, std.string, std.algorithm, std.range, 
std.datetime, std.conv, std.typetuple;

int f(string fileName = r"C:\Euler\data\e67.txt") {
    auto text = read(fileName);
    return text.length;
}

void main()
{
   try {
       string fileName = r"C:\Euler\data\e67.txt";
       auto text = read(fileName);
       writeln(text.length);

       writeln(f);  // **** EXCEPTION HERE
    }
    catch (Exception e) {
       writeln(e);
    }

    writeln(f);
}

I'm running this test code compiled with DMD 2.063.2 on Windows 7 
and I'm getting an exception "The system cannot find the file 
specified". The same code runs fine on Linux. The file in 
question exists of course.

When I remove the default parameter value from f(), exceptions 
stop. Is there a problem of having two strings 
r"C:\Euler\data\e67.txt" with the same content?
Aug 27 2013
next sibling parent reply "Paul Jurczak" <pauljurczak yahoo.com> writes:
Correction to my initial post:

I oversimplified the code example by snipping too much of 
context. Here is an example, which fails both on Windows and 
Linux:

module main;

import std.stdio, std.file, std.string, std.algorithm, std.range, 
std.datetime, std.conv, std.typetuple;

int e67_1(string fileName = r"67.txt") {
    // Read triangle numbers from file.
    int[][] cell;

    foreach (y, line; splitLines(cast(char[]) read(fileName))) {
       auto row = new int[y+1];

       foreach (x, token; split(line))
          row[x] = to!int(token);

       cell ~= row;
    }

    // Compute maximum value partial paths ending at each cell.
    foreach (y; 1..cell.length) {
       cell[y][0] += cell[y-1][0];

       foreach (x; 1..y)
          cell[y][x] += max(cell[y-1][x-1], cell[y-1][x]);

       cell[y][y] += cell[y-1][y-1];
    }

    // Return the maximum value terminal path.
    return cell[$-1].reduce!max;
}


void main()
{
    try {
       writeln(e67_1);
    }
    catch (Exception e) {
       writeln(e);
    }
}

Here is the message on Linux:

std.file.FileException std/file.d(219): 67.txt: No such file or 
directory
----------------
./main(void[] std.file.read(const(char[]), ulong)+0x87) [0x4c5b2b]
./main(int main.e67_1(immutable(char)[])+0x41) [0x4805a9]
./main(_Dmain+0x56) [0x4807de]
./main(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void runMain()+0x18) [0x4b8e60]
./main(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void tryExec(scope void 
delegate())+0x2a) [0x4b8992]
./main(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void runAll()+0x40) [0x4b8eb0]
./main(extern (C) int rt.dmain2._d_run_main(int, char**, extern 
(C) int function(char[][])*).void tryExec(scope void 
delegate())+0x2a) [0x4b8992]
./main(_d_run_main+0x1ae) [0x4b894e]
./main(main+0x17) [0x4b879b]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) 
[0x7ff2929ccea5]

Again, the file requested exists. I test that by adding other 
functions (from my initial post) to the code above.
Aug 27 2013
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 27 August 2013 at 17:14:23 UTC, Paul Jurczak wrote:
 Correction to my initial post:
I'll investigate later then.
Aug 27 2013
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 27 August 2013 at 17:19:08 UTC, monarch_dodra wrote:
 On Tuesday, 27 August 2013 at 17:14:23 UTC, Paul Jurczak wrote:
 Correction to my initial post:
I'll investigate later then.
I am unable to reproduce.
Aug 27 2013
parent reply "Ramon" <spam thanks.no> writes:
I played a little with it

int f(string fileName = r"someExistingPath") {
    auto text = read(fileName);
    return text.length;
}

void main()
{
   try {
       string fileName = r"someExistingPath";
       if(exists(fileName))
          writeln("File '", fileName, "' does exist.");
       auto text = read(fileName);
       writeln(text.length);

       writeln(f);  // **** EXCEPTION HERE
    }
    catch (Exception e) {
       writeln(e);
    }

    writeln(f);
}

As you see, I mistrustingly inserted a dumb exist test before 
attempting to read.

Here's what I came up with (on linux):

- trying with filename r"~/text.txt" (i.e. an existing file in my 
home dir) it FAILED.

- trying with the same filename but this time home dir 
explicitely written out fully (r"/home/me/test.txt) it WORKED.

- your code did NOT throw where you say it does ("writeln(f)") 
but actually in the read call.

Conclusion: I assume D's OS path related mechanisms to be 
somewhat dumb. Anyway the code throws where it's supposed to, 
i.e. when confronted with a non existing (or not recognized?) 
path.
Aug 27 2013
next sibling parent reply Justin Whear <justin economicmodeling.com> writes:
On Wed, 28 Aug 2013 00:51:12 +0200, Ramon wrote:

 
 - trying with filename r"~/text.txt" (i.e. an existing file in my home
 dir) it FAILED.
 
 - trying with the same filename but this time home dir explicitely
 written out fully (r"/home/me/test.txt) it WORKED.
 
 Conclusion: I assume D's OS path related mechanisms to be somewhat dumb.
 Anyway the code throws where it's supposed to, i.e. when confronted with
 a non existing (or not recognized?) path.
You need to use the expandTilde function: http://dlang.org/phobos/
Aug 27 2013
parent "Ramon" <spam thanks.no> writes:
Justin Whear & H.S. Teoh

Yep, that's what I assumed, too.

But that's so C Style. Wouldn't it befit phobos to have sth. like
normalizePath?

Like:

On Unix/linux rep ' ' with '\ '
        "       replace ~ with $HOME

etc. so as to have normalizePath return a path equal to what the
shell would do?

Well, whatever, I hope the OP (Paul Jurczak) could solve the
problem.

A+ - R
Aug 27 2013
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Aug 28, 2013 at 12:51:12AM +0200, Ramon wrote:
[...]
 Here's what I came up with (on linux):
 
 - trying with filename r"~/text.txt" (i.e. an existing file in my
 home dir) it FAILED.
 
 - trying with the same filename but this time home dir explicitely
 written out fully (r"/home/me/test.txt) it WORKED.
[...] That's because '~' is expanded not by the OS but by the shell. The OS treats it as a directory with the literal name '~', which doesn't exist. D's file I/O functions don't go through the shell. std.path.expandTilde is your friend. :) T -- This sentence is false.
Aug 27 2013
prev sibling parent "Paul Jurczak" <pauljurczak yahoo.com> writes:
On Tuesday, 27 August 2013 at 17:19:08 UTC, monarch_dodra wrote:
 On Tuesday, 27 August 2013 at 17:14:23 UTC, Paul Jurczak wrote:
 Correction to my initial post:
I'll investigate later then.
monarch_dodra, H. S. Teoh, Ramon, Justin Whear, Jesse Phillips: Sorry for the delay in responding - I had to take a nap and it helped to find the error I made. I noticed that the file path name was misspelled by one character in one of the test cases. Now everything works fine with both relative and absolute paths. Thank you for your help and I'm sorry for this wild goose chase.
Aug 27 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Aug 27, 2013 at 07:14:22PM +0200, Paul Jurczak wrote:
 Correction to my initial post:
 
 I oversimplified the code example by snipping too much of context.
 Here is an example, which fails both on Windows and Linux:
 
 module main;
 
 import std.stdio, std.file, std.string, std.algorithm, std.range,
 std.datetime, std.conv, std.typetuple;
 
 int e67_1(string fileName = r"67.txt") {
    // Read triangle numbers from file.
    int[][] cell;
 
    foreach (y, line; splitLines(cast(char[]) read(fileName))) {
Maybe try inserting a writeln just before the foreach to print out what filename it's actually trying to read? Or try using File to open it and see if you get the same error? auto f = File(fileName, "r"); T -- Ignorance is bliss... until you suffer the consequences!
Aug 27 2013
prev sibling parent "Jesse Phillips" <Jesse.K.Phillips+D gmail.com> writes:
On Tuesday, 27 August 2013 at 17:14:23 UTC, Paul Jurczak wrote:
 Correction to my initial post:

 I oversimplified the code example by snipping too much of 
 context. Here is an example, which fails both on Windows and 
 Linux:
I get a range violation in Linux, but that is to be expected since my file is empty. Removing the file gives the file not found exception.
Aug 27 2013
prev sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Tuesday, 27 August 2013 at 15:45:06 UTC, Paul Jurczak wrote:
 module main;

 import std.stdio, std.file, std.string, std.algorithm, 
 std.range, std.datetime, std.conv, std.typetuple;

 int f(string fileName = r"C:\Euler\data\e67.txt") {
    auto text = read(fileName);
    return text.length;
 }

 void main()
 {
   try {
       string fileName = r"C:\Euler\data\e67.txt";
       auto text = read(fileName);
       writeln(text.length);

       writeln(f);  // **** EXCEPTION HERE
    }
    catch (Exception e) {
       writeln(e);
    }

    writeln(f);
 }

 I'm running this test code compiled with DMD 2.063.2 on Windows 
 7 and I'm getting an exception "The system cannot find the file 
 specified". The same code runs fine on Linux. The file in 
 question exists of course.

 When I remove the default parameter value from f(), exceptions 
 stop. Is there a problem of having two strings 
 r"C:\Euler\data\e67.txt" with the same content?
Works for me on my own win7 with 2.063.2 (replaced file with r"C:\D\test.txt"). Not sure what else is going on. Did you copy paste the *exact* code that was failing? Please try inserting this trace: int f(string fileName = r"C:\D\test.txt") { writeln("fileName: ", fileName); //HERE auto text = read(fileName); return text.length; } And report what happens. Off topic, "text" might be a poor choice for a variable name, as it shadows the pretty common function "std.conv.text"
Aug 27 2013