Download Reference Manual
The Developer's Library for D
About Wiki Forums Source Search Contact

programs not running

Moderators: kris

Posted: 10/31/08 07:43:19

Welcome everyone! This is me first post, and me english is way far from excellence... As i am not a programmer, but a beginner in D/Tango, it is quite difficult to solve problems basing on net sources (forums, wikis etc) only. So please, be patient ;)
I am having a problem with my program, which compiles without a single error, but throws them during running (if I can call it "running"..) Trying to write a D code which would get some information (particularly number) from a file and append it to a variable. I found some examples in a great book - Apress, "Learn Tango with D", like:

import tango.io.Stdout;
import tango.io.FileConduit;
import tango.io.stream.DataFileStream;

void main()
{
     auto file = new FileConduit ("some_file.txt");
     auto input = new DataFileInput (file);
     int x = input.getInt;
     Stdout.formatln("X equals: {}", x);
     scope (exit) file.close;
}

As I said, this can be easilly compiled, but if I try to run it, I get:

tango.core.Exception.IOException: end-of-flow whilst reading

Similarly with this:

import tango.io.Stdout;
import tango.io.FileConduit;
import tango.text.convert.Format;
import tango.io.stream.DataFileStream;

void main()
{      
       char[] a = cast(char[]) File("some_file.txt").read;
       int x = atoi(a);                  // ### or x = a.parse(); ###
       Stdout.formatln("X equals: {}", x);
}

and the error is:

tango.core.Exception.IOException: unexpected eof

I already mentioned I learn D/Tango only for my purposes and pleasure and can't work it out.

wodzu777

Author Message

Posted: 10/31/08 09:39:33

Hi wodzu, welcome to you :)

What are the contents of some_file.txt ?

Posted: 10/31/08 09:53:48 -- Modified: 10/31/08 09:55:42 by
wodzu777

Hi Larsivi! There are just integers in the file.

Thanks for the reply.

Posted: 10/31/08 11:12:22

Could you paste an example?

Posted: 10/31/08 11:37:15

Aright. Not sure what exactly you want but will try..
So: I got a file, lets say: "some_file.txt" which stores e.g. "1" or "2" (definitely nothing more than 'byte' type). Now I need to check what number is in the file (it changes from time to time). As I wrote before, found some code in the book and the examples you got above in my first post. It compiles without a word, but does not run (throwing the above errors).

Greetz from Poland ;)

Posted: 10/31/08 12:01:41

I think that is what I wanted, something I can use to try to reproduce your problem :) Will look at it in the evening if noone gets to it before me.

Hmm, did I meet you at the conference? :)

Posted: 10/31/08 12:07:03

Ok, cheers mate!

Conference, you say? :> But what conference? As I can't remember any, haha.

wodzu777

Posted: 10/31/08 12:30:45

This conference

Posted: 10/31/08 13:11:42 -- Modified: 11/03/08 17:48:10 by
wodzu777

Anyone is able to reproduce thiese errors?

Posted: 11/03/08 18:22:52

I can confirm #1, the crucial line is this:

tom@Inges:~/d/tango$ echo 1 > some_file.txt
tom@Inges:~/d/tango$ ./foo
tango.core.Exception.IOException: end-of-flow whilst reading

input.getInt wants to grab an int, i.e. at least four bytes. Hence:

tom@Inges:~/d/tango$ echo 1234 > some_file.txt
tom@Inges:~/d/tango$ ./foo
X equals: 875770417

This is probably not exactly what you wanted, but technically correct :-)

Ciao

Tom

Posted: 11/03/08 21:33:22

Hi wodzu,

It can be confusing, but basically to explain what DataFileStream does is it reads/writes binary data. That is, if you store a 4-byte integer, it writes 4 bytes to the file, which are exactly the binary bytes needed to recreate the integer.

The file you have created contains a text representation of an integer, with one byte per decimal digit.

What you probably want is tango.text.convert.Integer.

You can probably get the result you are looking for like this:

import tango.io.Stdout;
import tango.io.FileConduit;

//
// rename all the Integer functions to be under the Integer namespace
//
import Integer = tango.text.convert.Integer;

void main()
{
    auto file = new FileConduit("some_file.txt");

    // do your scope exit here, this way if an error happens, your file is always closed
    scope(exit) file.close();

    char[1024] buffer;

    // read the data from the file
    int len = file.read(buffer);

    // trim all the data that is not an integer (i.e. newlines)
    while(len >0 && (buffer[len-1] < '0' || buffer[len-1] > '9'))
        len--;

    // parse text representation of integer into binary data.
    int x = Integer.parse(buffer[0..len]);

    Stdout.formatln("X equals: {}", x);
}

I tested this and it works:

[steves@localhost]$ echo 1234 > some_file.txt
[steves@localhost]$ ./teststuff
X equals: 1234
[steves@localhost]$

-Steve

Posted: 11/04/08 03:14:38 -- Modified: 11/04/08 03:21:06 by
kris

At this time there is no explicit facility for parsing mixed text values (numbers, strings, booleans, arrays, etc) from an input stream, such as a file or socket. There is support for parsing xml, and json (where json is probably more appropriate), and there is support for reading and writing binary values and arrays thereof.

The difficulty with implementing a generalized text parser is not the code itself, but the D language facilities. More explicitly, D does not support ref-varargs meaning it's not currently feasible to write a convenient symmetrical API for such purposes. At least two implementations have been attempted over the past four years, but neither has gained any traction that I know of.

In other words: we'd really like to have a reading/parsing facility that acts as the inverse of Stdout.formatln(), but that's not yet fully feasible in D.

Things are not as quite bad as they might seem though ... the above illustration with Integer.parse() is much stricter than need be, for example. You can pass it any old text string and it will extract what it can (and optionally tell you how much of the input it consumed):

import tango.io.File;

import Integer = tango.text.convert.Integer;

auto text = cast(char[]) File("myfile").read;
auto number = Integer.parse (text);

There are also facilities to split the input text into discrete chunks, based upon some provided delimiter. For example you could use text utilities, such as delimit(), in order to split comma separated values apart. What's missing (as noted above) is a handy utility to combine all such related facilities into one simple function.

Posted: 11/04/08 03:37:27

I tried the example above, and it operates as expected (no exceptions). I can't explain why it apparently didn't work for you ... puzzling

- Kris

Posted: 11/04/08 13:05:14

Thanks Guys!!! It realy helped and I understand more.

I do appreciate!

wodzu777

Posted: 11/04/08 14:36:29

kris wrote:

I tried the example above, and it operates as expected (no exceptions). I can't explain why it apparently didn't work for you ... puzzling

- Kris

Did you try it on a file with a single digit in it?

i.e.

echo 1 > some_file.txt

The exception only occurs if the file is less than 4 bytes (i.e. does not have enough binary info to contain an integer).

Posted: 11/04/08 15:48:47

no, but I tried the Integer.parse() version which the OP had also attempted

Posted: 11/04/08 20:51:55

Ah, didn't see that. I only focused on the data stream version.

Posted: 11/05/08 09:56:19

kris wrote:

Things are not as quite bad as they might seem though ... the above illustration with Integer.parse() is much stricter than need be, for example. You can pass it any old text string and it will extract what it can (and optionally tell you how much of the input it consumed):

import tango.io.File;

import Integer = tango.text.convert.Integer;

auto text = cast(char[]) File("myfile").read;
auto number = Integer.parse (text);

There are also facilities to split the input text into discrete chunks, based upon some provided delimiter. For example you could use text utilities, such as delimit(), in order to split comma separated values apart. What's missing (as noted above) is a handy utility to combine all such related facilities into one simple function.

Kris, I've just tried your example and it throws:

tango.core.Exception.IOException: unexpected eof

wodzu777

Posted: 11/05/08 15:03:29

According to the source of tango.io.File, this error occurs when the length returned by FileConduit does not match the length of the data read from the file.

So 1) can you tell us which file this is you are reading? Is it a file out of /proc (I know those lengths are incorrect)?

and 2) please execute the following code on the file, and tell us what it outputs (replace "yourfile" with your file name):

import tango.io.Stdout;
import tango.io.FileConduit;

void main()
{
auto fc = new FileConduit("yourfile");
auto len = fc.length;
Stdout.formatln("length is {}", len);
auto buf = new char[len];
auto bytesread = fc.read(buf);
Stdout.formatln("bytesread is {}", bytesread);
}

Posted: 11/07/08 18:22:12

The result is:

length is 4096
bytesread is 3


Thanks for your patience..

wodzu777

Posted: 11/11/08 17:33:56

What file are you reading? Can you do the following from a command prompt:

ls -l myfile
wc -c myfile

Replacing myfile with the filename you are reading?

The problem is that lseek is telling Tango that the file is 4096 bytes in length, yet when the file is read, only 3 bytes are in the file.

So there are 2 problems here. One, your filesystem is not consistent (which I know happens in for example /proc). Two, it might be better for Tango to ignore the length of the file when trying to read the entire content. Granted, it helps to allocate a big enough buffer, but if the read length is less or more, then it probably should not be a failure.

Or else, there should be a function to read an entire file without verifying the length is correct.

Posted: 11/12/08 08:52:11 -- Modified: 11/12/08 09:01:16 by
wodzu777 -- Modified 2 Times

The results of the above commands match each other and it is 4096.

Am not sure if anything wrong is with the file system. It's reiserfs and it seems to be ok. The file is in /sys dir.

wodzu777

Posted: 11/12/08 16:38:46

The /sys filesystem is typically a virtual file system generated by the kernel, not reiserfs. Most likely, there is a peculiarity about the node in that filesystem that does not behave like a normal file. If you could tell me the exact file name, I could try and reproduce it. Then a ticket can be issued to see if we can resolve it.

Posted: 11/13/08 09:24:49

Sure, Schveiguy! But you'd have to have tp_smapi module working. It's /sys/devices/platform/smapi/ac_connected

The file should contain "1" or "0" number.

What I'm trying to do is a script that checks some parameters (e.g. battery level, ac adapter connection etc) to manipulate the behavior of the system. Every parameter is represented by a number in several files, like the one mentioned above.
Bash and C++ work here, but I decided to do it in D/Tango.

wodzu777

Posted: 11/13/08 15:31:28

I don't need to have the exact file, just a similar file.

I found the same problem with /sys/devices/platform/power/wakeup

when doing an ls -l, the length is 4096. when doing a wc -c the length is 4096. However, I think wc has optimized out the actual reading of all the data (my mistake), so it actually is just checking what the filesystem says is the length. Doing this:

cat /sys/devices/platform/smapi/ac_connected | wc -c

should probably result in a '3' output.

On the wakeup file, it results in a '1' output.

So the issue is that /sys nodes appear to always report 4096 bytes as the length even though the files themselves may not be that long.

I'll file a ticket for Kris to look at. Thanks!

Posted: 11/14/08 12:09:35

I got '2'.
Thanks a lot Schveiguy, Kris and Larsivi !

wodzu777