Component Files (jfiles)
Jfiles are component files for J data. A jfile can be thought of as a boxed list which is stored on file. An element of the boxed list is referred to as a component, and can store a noun of any type, shape or size. File components are numbered sequentially from 0 upwards.
To access the system (assuming you are using the standard profile):
This populates a locale jfiles with utility functions, and defines the following verbs in the z locale:
jcreate, jerase, jappend, jread, jreplace, jdup, jsize
jcreate creates a file.
jappend adds new items to the file. Each item added to the file is stored in a new component. Several items can be added to the file at a time.
jread reads items from file, and jreplace replaces items on file.
jdup duplicates a file, and jsize returns its size.
You can refer to a file either by its file name, or by its file handle. The default file extension is .ijf - this is used if no file extension is given.
You cannot delete components once created. If you need to reclaim space no longer required, either replace the components with empties, or else duplicate the file, copying only the components required.
jcreate creates a file. The right argument is the filename. Any existing file is overwritten. The result is 1 if successful, else 0. For example:
jcreate 'mydata' 1
Note that since the file extension was not specified, this actually creates a file named mydata.ijf.
Read and write file
jappend appends to file. The left argument is a boxed list, with each item in the list stored in a new file component. An open noun is treated as a single boxed item. The right argument is the filename. The result is the new component numbers created. For example:
'header' jappend 'mydata' 0 ('rec1';'rec2') jappend 'mydata' 1 2 (< <\1 2 3) jappend 'mydata' 3 (2 2$10 20 30 40) jappend 'mydata' 4
jread reads a file. The right argument is the filename, linked with one or more component numbers. The result has the same shape as the component numbers. For example:
> jread 'mydata';4 10 20 30 40
jread 'mydata';i.5 +------+----+----+-------------+-----+ |header|rec1|rec2|+-+---+-----+|10 20| | | | ||1|1 2|1 2 3||30 40| | | | |+-+---+-----+| | +------+----+----+-------------+-----+ jread 'mydata';i.2 2 +------+-------------+ |header|rec1 | +------+-------------+ |rec2 |+-+---+-----+| | ||1|1 2|1 2 3|| | |+-+---+-----+| +------+-------------+
jreplace replaces in the file. The result is the components replaced. For example:
(1000;'abcde') jreplace 'mydata';1 2 1 2 jread 'mydata';i.3 +------+----+-----+ |header|1000|abcde| +------+----+-----+
The left argument is reshaped if necessary to match the components in the right argument. For example, the following replaces components 1-3, each with the word 'reserved':
'reserved' jreplace 'mydata';1 2 3 1 2 3
jdup duplicates a file. The left argument is the new filename; if elided, the file is duplicated in place. The right argument is the source filename, optionally linked with one or more component numbers to be copied to the new file, in the order given. By default, the entire file is duplicated. The result is the number of components written. For example:
'newdata' jdup 'mydata' 5 'newdata' jdup 'mydata';2 0 1 3
jsize returns the file size, as 4 numbers:
- starting component number (0)
- number of components
- length of file in bytes (same as result of 1!:4)
- amount of free space that could be recovered by duplicating the file
jsize 'newdata' 0 5 1312 0
jerase erases a file, for example:
jerase 'newdata' 1
You can refer to a file either by its filename, or by its file handle if you have already opened the file. For most purposes we recommend using the filename. However, if you have a great deal of file activity, you may find it faster to open the file first, then use the file handle; this means the system does not have to open and close the file each time it is accessed. The utilities jopen and jclose in the jfiles locale can be used for this purpose. For example:
h=. jopen_files_ 'mydata'
... process file using handle h...
jclose_files_ h 1
Each file is structured as a header record, followed by data. The header record is as follows:
 version  starting component  number of components  file length  directory pointer  freelist pointer  sequence number
Each component is stored in its 3!:1 representation in a space that is a power of 2. This means that on average, the representation fills 75% of the space allocated, and allows some space for growing replaces. If the space required on replacement is less than half the space allocated, then the balance is freed up.
If you replace a component with a noun of smaller size, then this may result in some unused space. The system keeps track of this in the freelist, and attempts to reuse it where possible. The total free space available is given in the fourth element of the result of jsize, and this is the space that would be freed by duplicating the file using jdup.
32 and 64 bit Component Files
J Files can be read and written by either J32 or J64.
When J64 writes to a J32 file, it converts the file directory to J64 format. This is a one time change. The reverse does not happen, i.e. J32 writing to a J64 file preserves the file directory format.
When J32 reads J64 files, data will be converted if necessary. For example, integers in J64 might be converted to floating point in J32.
J32 cannot access a file more than 2GB in size. There is no such limitation for J64, so it is possible to create a file in J64 that cannot be read by J32.
J32 files created in J504 can be accessed by earlier versions of J. However, J64 files cannot be accessed by earlier versions of J.