Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Rich H.J for C programmers.2006.pdf
Скачиваний:
19
Добавлен:
23.08.2013
Размер:
1.79 Mб
Скачать

21. Input And Output

Foreigns

In J, all file operations are handled by foreigns which are created by the foreign conjunction !: . The foreigns are a grab-bag of functions and you would do well to spend some time glancing over their descriptions in the Dictionary so you'll have an idea what is available. All the foreigns defined to date in J are of the form m!:n with numeric m and n, and they are organized with m identifying the class of the foreign. For example, the foreigns for operations on files have m=1.

File Operations 1!:n; Error Handling

The foreigns 1!:n perform file operations. For ease of use I have given several of them names in jforc.ijs . To see the details of what they do, read the Dictionary.

Monad 1!:1 (ReadFile) has rank 0 . 1!:1 y takes a filename as y and produces a result that is a list of characters containing the text of the file. In our examples, the filename is a boxed character string; y can be a file number but we won't get into that.

s =. 1!:1 <'system\packages\misc\jforc.ijs' s

NB. File definitions for'J For C Programmers' NB. Copyright © 2002 Henry H. Rich

Dyad 1!:2 (WriteFile) has rank _ 0 . character string x to provide the contents. boxed character string or a file number.

('Test Data',CR,LF) 1!:2

1!:2 y writes to the file y, using the Any existing file y is overwritten. y is a

<'c:\Temp\temp.dat'

Dyad 1!:3 (AppendFile) has rank _ 0 . x 1!:3 y appends the character string x to the of file y (creating the file if it does not exist):

('Line 2',CR,LF) 1!:3 <'c:\Temp\temp.dat'

Monad 1!:55 (EraseFile) has rank 0 . 1!:55 y erases the file y with no prompting. Be careful: the power of J makes it possible for you to delete every file on your system with one sentence.

The special file number 2 sends output to the screen. The verb monad Display in jforc.ijs uses file number 2 to display its operand (which must be a character string) on the screen; you can put Display sentences in a long verb to see intermediate results. In most cases you will prefer to use printf, described below.

There are many other 1!:n foreigns to manage file locks, query directories, handle index read/write, and do other useful things. The Dictionary describes them, and I will add only that the description of 1!:12 is misleading: the length to be written is implied

125

by the string argument x and must not be included in y; therefore item 1 of y is a boxed scalar, rather than a boxed list of 2 integers as for 1!:11 .

Error Handling: u ::v, 13!:11, and 9!:8

When you deal with files you have to expect errors, which will look something like s =. 1!:1 <'c:\xxx\yyy.dat'

|file name error

| s=. 1!:1<'c:\xxx\yyy.dat' indicating that the file was not found.

You can set up your verbs to catch errors instead of interrupting with a message at the console. We will learn one way here and another later when we study control structures for J verbs. The compound u ::v has infinite rank, and can be applied either monadically or dyadically. u ::v executes the verb u first (monad or dyad, as appropriate); if u completes without error, its result becomes the result of u ::v; but if u encounters an error, v is then executed, and its result becomes the result of u ::v :

rerr =: 1!:1 :: (13!:11@(''"_))

rerr y will execute 1!:1 to read y; if that fails it will execute the foreign 13!:11 '' . 13!:11 '' produces as result the error number of the last error encountered. This means that if 1!:1 succeeds, the result of rerr will be a string, while if 1!:1 fails, the result will be a number:

rerr <'system\packages\misc\jforc.ijs'

NB. File definitions for'J For C Programmers' NB. Copyright © 2002 Henry H. Rich

rerr <'c:\xxx\yyy.dat'

25

You could use 3!:0 to see whether the result of rerr is a string or a number (2 means string, 1, 4, 8, or 16 means number). If you want to see the error message associated with an error number, there's a foreign 9!:8 to give you the list of errors:

25

{ 9!:8 ''

+-----------------

+

|file

number error|

+-----------------

+

Treating a File as a Noun: Mapped Files

Rather than reading a file and assigning the data to a noun, you can leave the data in a file and create a noun that points to the data. The data will be read only when the noun is referred to. This is called mapping the file to a noun.

J's facilities for mapping files are described in the Lab 'Mapped Files'. A quick example of a mapped file is

require 'jmf'

JCHAR map_jmf_ 'text'; 'system\packages\misc\jforc.ijs' after which the noun text contains the data in the file:

126

45 {. text

NB. File definitions for'J For C Programmers'

Moreover, if you assign a new value to text, the file will be modified.

If you are dealing with large files, especially read-only files or files that don't change much, mapping the files can give a huge performance improvement because you don't have to read the whole file. You must be very careful, though, if you map files to nouns, because there are unexpected side effects. If we executed

temp =: text

temp =: 'abcdefgh'

we would find that the value of text had changed too! (If you try this, use a file you don't mind losing). The assignment of text to temp did not create a copy of data of text, and when temp was modified, the change was applied to the shared data. If a file is mapped to a noun, you have to make sure that the noun, or any copy made of the noun in any verb you pass the noun to, is not changed unless you are prepared to have some or all of the other copies changed. This topic is examined in greater depth under 'Aliasing of Variables' in the chapter on DLLs.

If the faster execution is enticement enough for you to take that trouble, you can consult the Lab to get all the details.

Format Data For Printing: Monad And Dyad ":

Since J reads and writes all files as character strings, you will need to be able to convert numbers to their character representation. Dyad ": has rank 1 _ . y may be numeric or boxed, of any rank (we will not consider boxed y here). If x is a scalar it is replicated to the length of a 1-cell of y . If y is numeric, each 1-cell of y produces a character-list result, with each atom in the 1-cell of y being converted to a character string as described by the corresponding atom of x and with the results of adjacent 0-cells being run together; the results from all 1-cells are collected into an array using the frame with respect to 1-cells. That sounds like the description of a verb with rank 1; almost so but not quite, because ": looks at the entire y and adds extra spaces as necessary to make all the columns line up neatly.

A field descriptor in x needs two numbers, w and d . These are represented as the real and imaginary parts of a complex number, so that only a single scalar is needed to hold the field descriptor. The real part of the field descriptor is w, and it gives the width of the field in characters. If the result will not fit into the field, the entire field is filled with asterisks; to prevent this you may use a w of 0 which will cause the interpreter to make the field as wide as necessary. The imaginary part of the field descriptor is d, giving the number of digits following the decimal point. If either w or d is less than zero, the result is in exponential form (and the absolute value of w or d gives the corresponding width), otherwise the result is in standard form. Examples:

127

0

0 ": i. 4 4

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

Note that extra spaces were added to the one-digit values to make them line up. Note also that 'enough space' includes a leading space to keep adjacent results from running together.

1 ": i. 4 4

0123

4567

89**

When you specify a width, you are expected to mean it, and no extra space is added. Here two-digit results would not fit and were replaced with '*'.

0

0 0j3

0j_3 ": 100 %~ i. 3 3

0.010

2.000e_2

0

0.040

5.000e_2

0

0.070

8.000e_2

A complex number has its parts separated by 'j' . Here the first field is an integer, the second has 3 decimal places, and the third is in exponential form.

When dyad ": is applied to an array, the result has the same rank as y . If you need to write that result to a file, you will need to use monad , to convert it to a list, possibly after adding CR or LF characters at the ends of lines.

Monad ":

Monad ": resembles dyad ": with a default x, except that x depends on the value of the corresponding atom of y . The simple description of monad ": is that it formats numbers the way you'd like to see them formatted. The full description is as follows: The precision d is given by a system variable that can be set by the foreign 9!:11 y (and queried by 9!:10 y; initially it is 6) ; as a quick override you may use the fit conjunction ":!.d to specify the value of d for a single use of ": . If an atom of y is an integer, a field descriptor of 0 is applied; if the atom has significance in the first 4 decimal places, a field descriptor of 0jd is applied; otherwise a field descriptor of 0j_3 is applied. Trailing zeros below the decimal point are omitted.

9!:10 ''

6

": 0 0.01 0.001 0.000015 0.12345678 2 0 0.01 0.001 1.5e_5 0.123457 2

In spite of all the detail I gave about the default formatting, in practice you just apply monad ": to any numeric operand and you get a good result. Monad ": accepts character arguments as well and leaves them unchanged:

; ":&.> 'Today ';'is ';2002 1 24 Today is 2002 1 24

We went inside the boxes with &.> and formatted each box's contents with monad ":; this made all the contents strings and we could run them together using monad ; .

128