## File Class

This chapter describes the File class, which provides methods and properties for reading from and writing to external files and discusses the following topics:

• Data type of a file object

• Scope of a file object

• File security considerations

• File access interruption recovery

• Plain text files

• Automatic PeopleCode generation

• File layout error processing

• File class built-in functions

• File class methods

• File class properties

• File layout examples

• Multiple file layouts

Constructing File Layouts and Performing Data Interchanges

### Understanding File Layout

PeopleTools supports reading and writing to plain text files, and to files that have a format based on a File Layout definition that has been created in Application Designer.

• If the file is a plain text file, data is read or written using text strings.

• If the file is based on a File Layout, you can use text strings, rowset, or record objects.

This simplifies reading, writing, and manipulating hierarchical transaction data with PeopleCode.

File layout methods and properties are noted as such in their descriptions.

Plain Text Files

File Layout Examples

Constructing File Layouts and Performing Data Interchanges

### Data Type of a File Object

The File Object is an instance of the File class. A file object is declared using the File data type. For example,

Local File &MYFILE;

This creates an object &MYFILE of the class File.

### Scope of a File Object

A file object can only be instantiated from PeopleCode. This object can be used anywhere you have PeopleCode, that is, in an application class, Component Interface PeopleCode, record field PeopleCode, and so on.

A file object is passed to and returned from PeopleCode functions and methods as a reference, so the file object is never copied; rather, alternate identifiers are used to refer to the same object. Any change made to a file using one identifier has the same effect as it would with any other identifier for that file.

In the following code example, two variables, &F1 and F2, are declared by using the data type File. The file is opened using the GetFile built-in function. Next, &F1 is assigned to &F2. This does not copy &F1 to &F2. Instead, &F1 and &F2 both refer to the same object. Therefore, in the last step when &F2 is closed, &F1 is closed too.

Local File &F1, &F2;

&F1 = GetFile("somefile.txt", "R");
If &F1.IsOpen Then
&F2 = &F1;
&F2.Close();  /* Now &F1 is also closed. */
End-if;

GetFile

Assigning Objects

### File Security Considerations

When you’re using file objects in PeopleCode that might run on a server, you must be aware of some security concerns. The underlying system doesn’t provide security checks on access to the files. Instead, the PeopleCode programs use whatever authority the server process has, and not that of the user. This means you must write your PeopleCode program to prevent the user from reading or writing files that they should not. In particular, be especially wary of opening files where any part of the filename is derived from user input.

### File Access Interruption Recovery

You can use the GetPosition or SetPosition methods to minimize the loss of work in the event of a system failure during file access. To use them and recover from access interruptions, you must access the file in Update mode using the GetFile built-in function or the Open method, specifying the mode parameter "U". You need to use this mode in anticipation of possible interruptions if you want to recover from them later.

To start reading or writing from the beginning of a file, use SetPosition to set a read/write position of 0, immediately after you open the file in Update mode.

Warning! In Update mode, any write operation clears the file of all data that follows the position you set.

When reading from or writing to a file, use GetPosition periodically to determine your current byte position in the file. This establishes a checkpoint to which you can return after a failure. You must save the checkpoint value in a separate file or a database so you can retrieve it later. How often you save a checkpoint depends on your requirements: the less work you want to redo, the more frequent your checkpoints should be. You may also want to save information identifying the data you’re reading or writing at the time.

After a failure interrupts your file access, reopen the file in Update mode. You can then retrieve the last checkpoint value you saved, and use SetPosition to apply that value. Your read/write position in the file is the position of the last checkpoint, and you can continue reading or writing from there.

Use the Update mode with GetPosition and SetPosition only for recovering from interruptions as described here, or for starting at the beginning of the file again.

Note. For fixed-width file layouts, the field start positions and lengths are computed in 8-bit bytes, except in the case of UCS2 or UTF-16 where they are computed in 16-bit double-bytes. This may create complications when using variable width encodings (for example, UTF-8 or Shift-JIS), when the data is elsewhere calculated in characters (rather than bytes), because the data involved may contain characters of varying byte-width.

Open

SetPosition

GetPosition

GetFile

### Plain Text Files

To read and write from plain text files involves reading and writing strings of data. These text strings can be manipulated with built-in string functions, like RTrim, Find, Replace, and so on.

Note. If your data is hierarchical in nature, or based on existing PeopleSoft records or pages, use a File Layout definition for reading and writing your data, rather than doing it line by line (or field by field.)

The following example creates an array of array of string, then reads in two files, one into each "column" of the array. The Names file contains names; the Numbers file contains employee numbers. The ReadLine method reads each successive line in a file, until it reaches the end of the file.

Notice that the first file is opened using the GetFile function. The second file is not opened using GetFile, but rather with the Open method. After the data is read into the array, you can do processing on the data. The end of the program writes the changes back to the files, using the WriteLine method, which includes a system end of line character at the end of every line.

Local array of array of string &BOTH;
Local File &MYFILE;
Local string &HOLDER;

/* Create empty &BOTH array */
&BOTH = CreateArrayRept(CreateArrayRept("", 0), 0);

/* Read first file into first column */

&MYFILE = GetFile("names.txt", "R");
&BOTH.Push(&HOLDER);
End-While;

/* read second file into second column */

&MYFILE.Open("numbers.txt", "R");
&LINENO = 1;
If &LINENO > &BOTH.Len Then
/* more number lines than names, use a null name */
&BOTH.Push(CreateArray("", &HOLDER));
Else
&BOTH[&LINENO].Push(&HOLDER);
End-If;
&LINENO = &LINENO + 1;
End-While;

/* if more names than numbers, add null numbers */
For &LINENO = &LINENO to &BOTH.Len
&BOTH[&LINENO].Push("");
End-For;
&MYFILE.Close();
​/* do processing with array */
​/* write data back to files */

&MYFILE1 = GetFile("names.txt", "A");
&MYFILE2 = GetFile("numbers.txt", "A");

/* loop through array and write to files */

For &I = 1 To &BOTH.Len
&STRING1 = &BOTH[&I][1];
&MYFILE1.writeline(&STRING1);
&STRING2 = &BOTH[&I][2];
&MYFILE2.writeline(&STRING2);
End-For;

&MYFILE1.Close();
&MYFILE2.Close();

File Layout Examples

### Automatic PeopleCode Generation

After you create a File Layout definition, you can use PeopleCode to access it. This PeopleCode can be long and complex. Rather than write it directly, you can drag and drop the File Layout definition from Application Designer Project View into an open PeopleCode edit pane. This is primarily used for importing data. Application Designer analyzes the definition and generates initial PeopleCode as a template, which you can modify to meet your requirements.

The following is just a snippet of the code that is generated:

Function EditRecord(&REC As Record) Returns boolean ;
Local integer &E;
REM   &REC.ExecuteEdits(%Edit_Required + %Edit_DateRange + %Edit_YesNo + %Edit_⇒
TranslateTable + %Edit_PromptTable + %Edit_OneZero);
&REC.ExecuteEdits(%Edit_Required + %Edit_DateRange + %Edit_YesNo + %Edit_One⇒
Zero);
If &REC.IsEditError Then
For &E = 1 To &REC.FieldCount
&MYFIELD = &REC.GetField(&E);
If &MYFIELD.EditError Then
&MSGNUM = &MYFIELD.MessageNumber;
&MSGSET = &MYFIELD.MessageSetNumber;
&LOGFILE.WriteLine("****Record:" | &REC.Name | ", Field:" |⇒
&MYFIELD.Name );
&LOGFILE.WriteLine("****" | MsgGet(&MSGSET, &MSGNUM, ""));
End-If;
End-For;
Return False;
Else
Return True;
End-If;
End-Function;
.
.
.

Constructing File Layouts and Performing Data Interchanges

### End Of Line Considerations

Input files for file layouts of type fixed or CSV must not contain embedded CR/LF within the field data.

However, input files for file layouts of type XML can contain embedded CR/LF within field data for a character type file field that is the associated with a long-character type database field that has unlimited length—that is, the maximum length specified as 0.

### File Layout Error Processing

If an error occurs on any field in any record of a rowset object populated with the ReadRowset method, the rowset object’s property IsEditError returns True. For example, you can use the method ExecuteEdits on a record, to verify that the data in the record is valid (has the correct format, the right data type, and so on.) This type of error is indicated by the IsEditError.

In some instances, however, the rowset object won’t receive the error; in that case the file object’s IsError property returns True. To discover all field errors, check both properties after executing ReadRowset.

To determine which field has the error, you must examine the EditError property of every field in the rowset to find the one returning True. You can then examine that field’s MessageSetNumber and MessageNumber properties to determine the relevant error message. The following example shows how this might be done:

&MYFILE.Open(&SOMENAME, "R");
&MYFILE.SetFileLayout(FILELAYOUT.SOMELAYOUT);
If &MYFILE.IsError Then
For &I = 1 to &MYROWSET.ActiveRowCount
If &MYROWSET.GetRow(&I).IsEditError Then
&ROW = &MYROWSET.GetRow(&I);
For &J = 1 to &ROW.RecordCount
If &ROW.GetRecord(&J).IsEditError Then
&REC = &ROW.GetRecord(&J);
For &K = 1 to &REC.FieldCount
If &REC.GetField(&K).EditError Then
/* Examine the field&rsquo;s
MessageSetNumber and MessageNumber properties,
and respond accordingly */
End-If;
End-For;
End-If;
End-For;
End-If;
End-For;
End-If;

&MYFILE.Close();

Note. Only field errors set the IsError, IsEditError, or EditError properties. All other errors triggered by File class methods terminate the PeopleCode program.

IsError

IgnoreInvalidId

IsEditError

ExecuteEdits

ExecuteEdits

MessageNumber

MessageSetNumber

CreateDirectory

FileExists

FindFiles

GetFile

GetTempFile

### File Class Methods

In this section, we discuss the File class methods. The methods are discussed in alphabetical order.

#### Close

Syntax

Close()

Description

The Close method discards any changes that haven’t been written to the external file, disassociates the file object from the external file, releases all resources connected with the file object, and causes the file object to go out of scope.

You cannot use any methods or properties on the object after it is closed. You must get another file object (using the GetFile function) and instantiate another file object after you use Close.

Parameters

None.

Returns

None.

Example

&MYFILE.Open("somefile.txt", "W", %FilePath_Relative);
&MYFILE.WriteLine("Some text.");
&MYFILE.Close();

File class: Open method, IsOpen property.

GetFile

#### CreateRowset

Syntax

CreateRowset()

Description

The CreateRowset method is a file layout method. It instantiates a PeopleCode rowset object containing one unpopulated row, based on the file layout definition specified with SetFileLayout.

Note. You must specify a file layout using the SetFileLayout method before using CreateRowset, otherwise it returns NULL.

See File class: SetFileLayout method.

After the empty rowset object has been created, you can use Rowset class methods such as Select or Fill, and built-in functions such as GetLevel0 or GetRowset, to populate the rowset with data. After the rowset contains data, you can use the method WriteRowset to write the data to a file.

Don’t use CreateRowset when reading from a file. Instead, use the ReadRowset method to instantiate and populate rowsets with data from the file.

Parameters

None.

Returns

An empty rowset object.

Example

&SOMEROWSET = &MYFILE.CreateRowset();

The following rowset is created from a file object, then populated with data using the GetLevel0 function:

&FILEROWSET = &MYFILE.CreateRowset();
&FILEROWSET = GetLevel0();
&MYFILE.WriteRowset(&FILEROWSET, True);

The following rowset is created from a file object, then populated with data using Fill method:

&FILEROWSET = &MYFILE.CreateRowset();
&NUM_READ = &FILEROWSET.Fill("where MYRECORD = :1", &UVAL);

File class: ReadRowset method, SetFileLayout method, WriteRowset method.

Rowset Class

#### Delete

Syntax

Delete()

Description

Use the Delete method to delete an open file. You cannot delete a closed file.

Parameters

None.

Returns

None.

Example

/* Open a temporary file. Use the "N" parameter to ensure
the file is new. */

&MyFile = GetFile("temp.txt", "N");

/* verify the file was instantiated successfully */

/* do processing using the temporary file */

/* delete the temporary file */

&MyFile.Delete();


File class: Open method, Close method.

GetFile

#### GetPosition

Syntax

GetPosition()

Description

The GetPosition method returns the current read or write position in the external file. GetPosition works only with a file that was opened in Update mode. This method is designed to be used in combination with the SetPosition method to establish checkpoints for restarting during file access.

Note. Currently, the effect of the Update mode and the GetPosition and SetPosition methods is not well defined for Unicode files. Use the Update mode only on files stored with a non-Unicode character set.

Parameters

None.

Returns

A number representing the current read or write position in the file.

Note. When you use ReadRowset to read from a file in Update mode, the CurrentRecord property returns, the entire record just read. The current read/write position is at the end of the CurrentRecord, that is, just past the end of the rowset.

Example

The following example opens a file in Update mode, and saves the current position after each read operation:

&MYFILE.Open(&SOMENAME, "U");
If &MYFILE.IsOpen Then
&CURPOS = &MYFILE.GetPosition();
/* Save the value of &CURPOS after each read,
and process the contents of each &SOMESTRING */
End-While;
End-If;
&MYFILE.Close();

File class: Open method, SetPosition method.

File Access Interruption Recovery

GetFile

#### GetString

Syntax

GetString([Strip_Line_Terminator])

Description

Use the GetString method to return the entire file as a single string.

Note. After this method completes successfully, the original file is deleted.

You can specify whether the resulting string is to include the line terminator characters or not by using the Strip_Line_Terminator parameter. The default value for this parameter is false, which means the resulting string includes the line terminator characters at the end of each line.

For example on a Unix system, with a line terminator of a LF, the resulting string includes not only the data for each line, but the LF character as well.

Parameters

 Strip_Line_Terminator Specify whether the line terminators are to be stripped or not.

Returns

A single string containing the entire contents of the file.

Example

The following example creates a file on a Windows system, then retrieves it as a single line of text.

Note. The file is destroyed on successful completion of this method.

Local File &File = GetFile("c:\temp\junk\something.txt", "W", %FilePath_Absolute)
/* write a bunch of > 2048 length lines */

Local string &piece, &input;
Local integer &I;

&piece = "123456789-";
While Len(&piece) < 2048
&piece = &piece | &piece;
End-While;

&File.WriteString(&piece);
&File.WriteString(&piece);
&File.WriteString(&piece);
&input = &File.GetString( True);
&File.Close();
Local string &pieces = &piece | &piece | &piece;

/* Note that the result of this message should indicate &pieces is the same as⇒
&input */
MessageBox(0, "", 0, 0, "&piece = &input: Len(&pieces)=" | Len(&pieces) | " Len⇒
(&input)=" | Len(&input) | " Same? " | (&pieces = &input));


File class: ReadLine method, WriteLine method, WriteRaw method.

#### Open

Syntax

Open(filespec, mode [, charset] [, pathtype])

Description

The Open method associates the file object with an external file for input or output.

If the File object is currently associated with a file, that file is closed first. In addition, any file opened for writing (by a call to the GetFile function or the Open method) by a PeopleCode program that runs in the Process Scheduler is automatically managed by the Report Repository.

You can use the GetFile or GetTempFile functions to access an external file, but each execution of GetFile or GetTempFile instantiates a new file object. If you plan to access only one file at a time, you need only one file object. Use GetFile or GetTempFile to instantiate a file object for the first external file you access. Then, use Open to associate the same file object with as many different external files as you want. However, if you expect to have multiple files open at the same time, you need to instantiate multiple file objects with GetFile or GetTempFile.

GetFile and Open both perform implicit commits. Therefore, the GetTempFile function has been introduced specifically to avoid these implicit database commits. GetTempFile differs from GetFile in two respects:

• GetTempFile does not perform an implicit commit.

• GetTempFile does not make the associated file available through the Report Repository even when the calling PeopleCode program is run through the Process Scheduler.

Therefore, GetTempFile can be a good choice when you wish to avoid implicit database commits and when you do not need to have the file managed through the Report Repository. Otherwise, GetTempFile operates exactly the same as GetFile.

Working With Relative Paths

If you specify a relative path, that path is appended to the path specified by an environment variable if the variable exists. Environment variables are searched for in a particular order. This means if the first environment variable in order is found, that's the one that is used. If it isn't found, the next one is searched for, and if found, is used, and so on.

If Open is called from an Application Engine program when running standalone—that is, when not within an application server domain—the following environment variables are valid and are searched for in the following order:

1. PS_FILEDIRrelative_path

2. PS_SERVDIR\files\relative_path

3. TEMP\relative_path

If Open is called from a program running within an application server domain, the following environment variables are valid and are searched for in the following order:

1. PS_FILEDIR\relative_path

2. PS_SERVDIR\files\relative_path

The PS_FILEDIR environment variable is not initialized and set to a path automatically. If you want to use this environment variable, you must set it yourself.

Note. In the preceding examples, the Windows directory separator, a backslash, was used. For UNIX directories, the directory separator is a forward slash.

Note. Your system security should verify if a user has the correct permissions before allowing access to a drive (for example, if a user changes their TEMP environmental variable to a network drive they don’t normally have access to, your system security should detect this.)

Parameters

Note. The syntax of the file path does not depend on the file system of the platform where the file is actually stored; it depends only on the platform where your PeopleCode is executing.

Returns

None.

Example

The following example opens an existing Unicode file for reading:

&MYFILE.Open(&SOMENAME, "E", "U");
If &MYFILE.IsOpen Then
/* Process the contents of each &SOMESTRING */
End-While;
&MYFILE.Close();
End-If;

The following example opens a numbered file for writing in ANSI format, without overwriting any existing files:

&MYFILE.Open("C:\temp\item*.txt", "N", %FilePath_Absolute);
If &MYFILE.IsOpen Then
&MYFILE.WriteLine("Some text.");
&MYFILE.Close();
End-If;

File class: IsOpen property, SetPosition method, GetPosition method, Close method.

File Access Interruption Recovery

GetFile, GetTempFile.

Syntax

ReadLine(string)

Description

The ReadLine method reads one line of text from the external file. The line includes the newline character, but ReadLine strips out the newline character and inserts the result into the string variable string.

When ReadLine is executed, it moves the starting point for the next read operation to the end of the text just retrieved, so each line in the file can be read in turn by subsequent ReadLine operations. When no more data remains to be read from the file, ReadLine returns False, and clears the string variable of any content.

Parameters

 string A string variable that receives the input text.

Returns

A Boolean value: True if the method succeeds, False otherwise. The return value is not optional, it is required.

Example

The following example reads a file called &MYFILE and puts each line as a separate element in an array.

Local File &MYFILE;
Local array of string &MYARRAY;
Local string &TEXT;

&MYFILE = GetFile("names.txt", "R");
&MYARRAY = CreateArrayRept("", 0);
&MYARRAY.Push(&TEXT);
End-While;
&MYFILE.Close();

File class: GetString method, ReadRowset method, WriteString method, WriteLine method.

Syntax

ReadRowset()

Description

The ReadRowset method is a file layout method. It instantiates a PeopleCode rowset object based on the file layout definition, then populates the rowset with one transaction from the file. A transaction is considered to be one instance of level zero data contained in a file record, plus all of its subordinate data. If you put more than one segment at level zero, each segment is read in sequence.

Note. You must specify a file layout using the SetFileLayout method before using ReadRowset, otherwise it will return NULL.

When ReadRowset is executed, it moves the starting point for the next read operation to the beginning of the next rowset, so each transaction in the file can be read in turn by subsequent ReadRowset operations. When no more data remains to be read from the file, ReadRowset returns NULL.

If you’re using the SetFileId method with ReadRowset to process an input file based on multiple file layouts, ReadRowset returns NULL when it reads a FileId file record (line) between the rowsets.

When ReadRowset returns NULL, you can use the IsFileId property to determine if you’ve reached the end of the file or a FileId record.

Note. When using ReadRowset, if a value in the file exceeds the defined length in the file layout, it is ignored. The given record field is flagged with an edit error which can be programmatically checked.

If the ReadRowset encounters a line in the file containing the FileId, and the lines following this are not a new rowset, the process considers it to be an invalid FileId. You can specify whether to ignore the invalid record or terminate the PeopleCode with the IgnoreInvalidId property.

Note. If you’re using the SetFileId method with ReadRowset to process an input file based on multiple layouts, FileId file records between the rowsets are considered to be valid file records, and won’t generate any errors, regardless of the state of the IgnoreInvalidId property.

See File class: SetFileLayout method.

Considerations for Using Dates With ReadRowset

Single digits in dates in the form MMDDYY or MMDDYYYY must be padded with zeros. That is, if the date in your data is February 3, 2000, the form must be:

02/03/2000

or

02/03/00

The following is not valid.

2/3/00

Considerations for Using XML With ReadRowset

If all of the fields in the file layout are not present in the XML, no data is written to the database. If there are additional tags in the XML, they are ignored.

Considerations for Using Nested Data with ReadRowset

If you are processing input files with a large amount of nested data, your application server may run out of memory before the system finishes processing all of the data.

This may happen because of the differences between processing a single-level rowset and a multi-level rowset. If you are reading the rows of a single-level (level 0) rowset from a file, the file is processed one row at a time, that is, only one row resides in memory at a time.

However, if you are reading the rows of a multi-level (parent-child) rowset from a file, then for each level 0 row, all of the associated child rows (and all of their associated child rows) simultaneously reside in memory. As a result, during the processing a large input data file that is associated with a multi-level rowset (through a multi-level file layout definition), your application server may run out of memory.

To work around this, consider doing one of the following:

• Retain your original file layout definition and split the original input file into smaller (but structurally unchanged) pieces

• Flatten out your original file layout definition (that is, split it up into several single-level definitions) as well as split the original input file into several single-level pieces.

Considerations for Using Default Values with ReadRowset

The system variables related to date and time (for example, %Date, %Time, and %DateTime) cannot be used to specify the value of the Default Value property of a file layout field. This topic is covered in detail in the Application Designer PeopleBook.

See Specifying File Layout Field Properties.

Parameters

None.

Returns

A populated rowset.

Example

The following example reads and processes an entire file. The data in the file is based on a single File layout definition:

&MYFILE.GetFile(&SOMENAME, "R");
If &MYFILE.SetFileLayout(FILELAYOUT.SOMELAYOUT) then
While &SOMEROWSET <> NULL
/* Process the contents of each &SOMEROWSET */
End-While;
End-If;
&MYFILE.Close();

File class: CurrentRecord property, IgnoreInvalidId property, GetString method, ReadLine method, SetFileLayout method, WriteRecord method, WriteRowset method.

Multiple File Layouts

IsEditError

#### SetFileId

Syntax

SetFileId(fileid, position)

Description

The SetFileId method is a file layout method. If your input file contains data based on more than one File Layout definition, you must use this method in combination with the CurrentRecord and IsNewFileId properties and the ReadRowset method to process the file correctly.

Note. SetFileId, CurrentRecord and IsNewFileId don’t apply to CSV and XML format input files. You can use only fixed format files to implement multiple file layouts.

See File class: CurrentRecord property, IsNewFileId property, ReadRowset method.

At each point in the input file where the structure of the rowset changes, there must be an extra line in the file containing the file record (line), the FileId file record (line), that signifies that the change. Each FileId file record must have the following components:

• A value that designates it as a Fileid. Only one FileId value is necessary throughout the file, such as "999".

• A name field that identifies the file layout needed for the rowset that follows. This field could contain the name of the file layout as it’s defined in Application Designer.

These lines containing the FileId are not part of any rowset. They can contain other information, which will be disregarded by the system. The FileId identifier and the file layout names aren’t automatically stored anywhere; they exist only in the input file’s FileId file records and in the PeopleCode.

To process an input file that requires multiple file layouts:

1. Use SetFileLayout to specify the file layout definition to use.

If you’re specifying the initial file layout for this file, it doesn’t have to be the correct one. You can determine the correct file layout to use for the first rowset during a subsequent step.

2. Use SetFileId to specify the value of the FileId field, fileid, that’s used throughout the file to designate FileId file records.

Note. After each execution of SetFileLayout, the SetFileId setting is disabled. Be sure to re-specify the FileId value if you expect the file layout to change, so the system continues looking for the next FileId file record.

The current file record is also stored in the CurrentRecord property as a string. The PeopleCode process determines whether it’s the beginning of a new rowset, or a FileId file record according to the fileid you specified. If it’s a FileId file record, the process sets the IsNewFileId property to True; if not, it sets the IsNewFileId property to False.

Note. If this is the first execution of ReadRowset on the file, it returns NULL upon encountering the initial FileId file record, but still stores that file record in CurrentRecord and sets IsNewFileId accordingly.

4. If the rowset returned isn’t NULL, process that rowset as necessary.

5. If IsNewFileId is False, go back to step 3 to continue reading rowsets from the file. If IsNewFileId is True, examine CurrentRecord to determine which new file layout to use, and go back to step 1.

You can repeat this procedure one rowset at a time, proceeding through the remainder of the input file. When ReadRowset returns NULL, no more rowset data is available.

Parameters

 fileid Specify the value of the FileId field used in the current file. position Specify the column in the FileId file record where the FileId field starts. The default is 1.

Returns

None.

Example

&rsFile = &MYFILE.ReadRowset();
&CurrentRecord = &MYFILE.CurrentRecord;
&IsNewFileID = &MYFILE.IsNewFileId;
If &MYFILE.IsNewFileId Then
&FILELAYOUT = FindFileID(&CurrentRecord);
&MYFILE.SetFileLayout(@("FileLayout." | &FILELAYOUT));
&MYFILE.SetFileId("999", 1);
End-If;

File class: CurrentRecord property, IsNewFileId property, ReadRowset method, SetFileLayout method.

File Layout Examples

Constructing File Layouts and Performing Data Interchanges

#### SetFileLayout

Syntax

SetFileLayout(FILELAYOUT.filelayoutname)

Description

The SetFileLayout method is a file layout method. It associates a specific file layout definition with the file object executing this method, providing easy access to rowset data. The file object must be associated with an open file. With file layout definitions, you can read and write rowsets as easily as strings. If the file object isn’t open or the definition doesn’t exist, SetFileLayout fails.

You must execute SetFileLayout before you can use any other file layout methods or properties with a file object, otherwise those methods and properties return NULL or False.

Note. All provided PeopleTools records that have a prefix of PSFLD are related to file layout definitions.

Parameters

 filelayoutname Specify as a string the name of an existing file layout definition created in Application Designer.

Returns

A Boolean value: True if the method succeeds, False otherwise.

Example

The following example opens a data file, associates a file layout definition with it, reads and processes the first rowset from it, and closes the file.

&MYFILE.Open(&SOMENAME, "E");
If &MYFILE.SetFileLayout(FILELAYOUT.SOMELAYOUT) then
/* Process the contents of &SOMEROWSET */
Else
/* Error - SetFileLayout failed */
End-If;
&MYFILE.Close();

File class: CurrentRecord property, CreateRowset method, ReadRowset method, IgnoreInvalidId property, WriteRowset method.

File Layout Examples

Constructing File Layouts and Performing Data Interchanges

#### SetPosition

Syntax

SetPosition(position)

Description

The SetPosition method sets the current read or write position in the external file associated with the file object executing this method. SetPosition works only with a file, which is opened in Update mode, and is designed to be used in combination with the GetPosition method to recover from interruptions during file access.

To start reading or writing from the beginning of a file, you must use SetPosition to set a read/write position of 0, immediately after you open the file in Update mode.

Parameters

 position The byte position in the file at which you want to continue reading or writing. This should either be 0 or a value you previously obtained with the GetPosition method and saved in a separate file or a database.

Warning! In Update mode, any write operation clears the file of all data that follows the position you set.

Note. Use SetPosition only for recovering from file access interruptions. Supplying your own value for SetPosition isn’t recommended, except for position 0.

Returns

None.

Example

The following example reopens a file in Update mode, and sets the read position to the last saved checkpoint:

&MYFILE = GetFile(&SOMENAME, "U");
If &MYFILE.IsOpen Then
/* Retrieve the value of the last saved checkpoint, &LASTPOS */
&MYFILE.SetPosition(&LASTPOS);
/* Process the contents of each &SOMESTRING */
End-While;
&MYFILE.Close();
End-If;

Note. Currently, the effect of the Update mode and the GetPosition and SetPosition methods is not well defined for Unicode files. Use the Update mode only on files stored with a non-Unicode character set.

File class: GetPosition method, Open method.

File Access Interruption Recovery

GetFile

#### SetRecTerminator

Syntax

SetRecTerminator(Terminator)

Description

The SetRecTerminator method is a file layout method.

Use this method to specify the string of characters that indicate the end of a file record. Read operations use the value of SetRecTerminator to determine where each file record ends and the next one starts, and write operations append the value of SetRecTerminator to each record written.

This value defaults to the newline character appropriate to the platform where the file is being stored:

• a linefeed on UNIX systems

• a carriage return/linefeed combination on Windows systems

You need to specify a different record terminators only if you anticipate that part of the data in a file field that includes the newline character used on the storage platform; you must assign the record terminator a unique string that you know does not appear in a file field.

If you set the record terminator to Null ("") you eliminate linefeeds or carriage returns.

Parameters

 Terminator Specify the value you want used for the record terminator.

Returns

None.

Example

&File = GetFile(......);

if &File.IsOpen then
/* set the terminator to be NULL */
Local String &Term = "";
&File.SetRecTerminator(&Term);

#### WriteLine

Syntax

WriteLine(string)

Description

The WriteLine method writes one string of text, string, to the output file associated with the file object executing this method, followed by a newline character appropriate to the platform where the file is being written. To build a single line using multiple strings, use the WriteString method.

Parameters

 string The string of text to be written.

Returns

None.

Example

The following example adds a line of text to an existing file:

&MYFILE.Open("somefile.txt", "A");
&MYFILE.WriteLine("This is the last line in the file.");
&MYFILE.Close();

The following example converts a file where the fields are separated with tabs into a file where the fields are separated with commas.

Local File &TABFILE, &CSVFILE;
Local string &FILE_NAME, &DATA, &NEWDATA;

&FILE_NAME = "Test.txt";
&TAB = Char(9);

&TABFILE = GetFile(&FILE_NAME, "r");
&FileName = &TABFILE.Name;
&POS = Find(".", &FileName);
&NEWFILE_NAME = Substring(&FileName, 1, &POS) | "dat";
&CSVFILE = GetFile(&NEWFILE_NAME, "N", %FilePath_Absolute);
If &TABFILE.IsOpen And
&CSVFILE.IsOpen Then
&NEWDATA = Substitute(&DATA, &TAB, ",");
&CSVFILE.WriteLine(&NEWDATA);
End-While;
&TABFILE.Close();
&CSVFILE.Close();
End-If;

File class: GetString method, ReadLine method, WriteString method, WriteRaw method.

#### WriteRaw

Syntax

WriteRaw(RawBinary)

Description

The WriteRaw method writes the contents of RawBinary to a file. This can be used for writing images, messages, or other types of raw binary data to a file.

Parameters

 RawBinary Specify the raw binary to be written to the file.

Returns

None.

Example

The following example writes employee photos (GIF files) from a record to a file.

Local File &FILE;
Local Record &REC;
Local SQL &SQL;

&REC = CreateRecord(Record.EMPL_PHOTO);
&SQL = CreateSQL("%SelectAll(:1)", Record.EMPL_PHOTO);

&FILE = GetFile("C:\temp\EMPL_PHOTO.GIF", "w", "a", %FilePath_Absolute);

While &SQL1.Fetch(&REC)
&FILE.WriteRaw(&REC.EMPLOYEE_PHOTO.Value);
End-While;

&FILE.Close();

File class: WriteLine method, WriteString method.

#### WriteRecord

Syntax

WriteRecord(record)

Description

The WriteRecord method is a file layout method. It writes the contents of the record object record, to the output file. (Remember, a record object contains only one row of data from an SQL table.)

You can use this method to build a transaction in the output file, one file record at a time, without having to instantiate and populate a rowset object. You can apply this method to any record whose structure and name matches that of a record defined in the current file layout.

Note. You must execute the SetFileId method from the file object before using WriteRecord, otherwise it returns False.

See File class: SetFileLayout method.

Note. When you're writing text to an XML file, special HTML characters, such as ampersands, lesser than or greater than symbols, and so on, are automatically converted to valid XML character string, such as &amp.

Considerations Using XML With File Definition Tags

File Definition Tags have no effect when importing data. However, generally, during export, the File Definition Tag is added at the start and end of the data to create a valid XML file.

The one exception is when the file to which the data is being written during export has been opened in append mode. At that time, the file definition tag is not taken into consideration.

Considerations Using XML with File Definitions

If your file layout is defined as XML, WriteRecord doesn't add the closing tag for the record. You must write it yourself using the WriteLine method. This is because the code has no way of knowing when you want to write children records following the record just written out.

The following code shows an example of using WriteLine:

Local File &MYFILE;

&MYFILE = GetFile("XMLrecord.txt", "A");

If &MYFILE.IsOpen Then
If &MYFILE.SetFileLayout(FILELAYOUT.RECORDLAYOUT) Then
&LN = CreateRecord(RECORD.QA_INVEST_LN);
&SQL2 = CreateSQL("%Selectall(:1)", &LN);
While &SQL2.Fetch(&LN)
&MYFILE.WriteRecord(&LN);
​WriteLine("</QA_INVEST_LN>"); /* Add the closing tag */
End-While;
Else
/* do error processing - filelayout not correct */
End-If;
Else
/* do error processing - file not open */
End-If;

&MYFILE.Close();


Parameters

 record Specify the name of an existing record object to be written. You can use Rowset class methods such as GetField and built-in functions such as GetRecord to populate the record with data before writing it to the file.

Returns

A Boolean value: True if the method succeeds, False otherwise. This value is optional.

Example

The following example appends all the data in a record to an existing file:

Local File &MYFILE;

&MYFILE = GetFile("record.txt", "A");

If &MYFILE.IsOpen Then
If &MYFILE.SetFileLayout(FILELAYOUT.VOL_TEST) Then
&LN = CreateRecord(RECORD.VOLNTER_ORG_TBL);
&SQL2 = CreateSQL("%Selectall(:1)", &LN);
While &SQL2.Fetch(&LN)
&MYFILE.WriteRecord(&LN);
End-While;
Else
/* do error processing - filelayout not correct */
End-If;
Else
/* do error processing -; file not open */
End-If;

&MYFILE.Close();

File class: CreateRowset method, ReadRowset method, SetFileLayout method, WriteRowset method.

Record Class

Accessing the Data Buffer

#### WriteRowset

Syntax

WriteRowset(rowset [, Write_Data])

Description

The WriteRowset method is a file layout method. It writes the contents of a rowset object, rowset, to the output file associated with the file object executing this method. Regardless of whether the rowset contains just one or more than one transaction (level zero row), executing this method once writes the entire contents of the rowset to the output file.

Note. You must execute the SetFileLayout method from the file object before using WriteRowset, otherwise it returns False.

See File class: SetFileLayout method.

WriteRowset writes a rowset to a file only if the data in the component buffer has changed. You must specify the WriteData parameter as True if you want the WriteRowset method to force the rowset to be written to the file even if the buffer has not been changed.

Note. When you're writing text to an XML file, special HTML characters, such as ampersands, lesser than or greater than symbols, and so on, are automatically converted to valid XML character string, such as &amp.

Considerations Using Fixed Length Files With Numeric Fields

All numeric fields are right-justified in when writing to fixed length files. In addition, zeros are padded to the right after the decimal point if required.

Considerations Using XML With File Definition Tags

File Definition Tags have no effect when importing data. However, generally, during export, the File Definition Tag is added at the starting and end of the data to create a valid XML file.

The one exception is when the file to which the data is being written during export has been opened in append mode. At that time, the file definition tag is not taken into consideration.

Parameters

 rowset Specify the name of an existing rowset object that was instantiated with the File class CreateRowset or ReadRowset method. You can use Rowset class methods such as Select and built-in functions such as GetLevel0 to populate the rowset with data before writing it to the file. WriteData Specify whether to write the rowset data to the file whether or not the data in the buffer has changed. This parameter takes a Boolean value: True, write the data to the buffer regardless, False, only write the data if changed. The default value for this parameter is False.

Returns

A Boolean value: True if the method succeeds, False otherwise.

Example

Local File &MYFILE;
Local Rowset &FILEROWSET;

&MYFILE = GetFile("c:\temp\EMP_CKLS.txt", "A", %FilePath_Absolute);
If &MYFILE.IsOpen Then
If &MYFILE.SetFileLayout(FILELAYOUT.EMPL_CHECKLIST) Then
&FILEROWSET = &MYFILE.CreateRowset();
&FILEROWSET = GetLevel0();
&MYFILE.WriteRowset(&FILEROWSET, True);
Else
End-If;
Else
/* file not opened, do error processing */
End-if;

&MYFILE.Close();

File class: CreateRowset method, ReadRowset method, SetFileLayout method, WriteRecord method, ZeroExtend property.

Record Class

Accessing the Data Buffer

#### WriteString

Syntax

WriteString(string)

Description

The WriteString method writes one string of text to the output file associated with the file object executing this method, without any newline character. Each string written extends the current line in the file.

You can start a new line by using the WriteLine method to write the last part of the current line. WriteLine always adds a newline character appropriate to the platform where the file is being written, whether you supply a character string of any length, or a null string.

Parameters

 string A string variable containing the text to be written.

Returns

None.

Example

The following example opens an empty file, writes two lines of text to it without a final newline, and closes it:

&MYFILE.Open("somefile.txt", "W");
&MYFILE.WriteString("This is the first ");
&MYFILE.WriteString("line in the file.");
&MYFILE.WriteLine("");
&MYFILE.WriteString("This second line is not terminated.");
&MYFILE.Close();

File class: ReadLine method, WriteLine method, WriteRaw method.

### File Class Properties

In this section, we discuss each File Class property.

#### CurrentRecord

Description

This property is a file layout property. This property returns the current record as a string. The CurrentRecord property is used in combination with the SetFileId and ReadRowset methods and IsNewFileId property when reading files that contain data based on multiple file layouts.

If the ReadRowset method returns NULL, either the current record is a FileId record or the end of file has been reached. The IsNewFileId enables you to determine which. If it is a FileId, you can parse the string returned by CurrentRecord to determine the file layout definition to be used.

Note. SetFileId, CurrentRecord, and IsNewFileId don’t apply to CSV and XML format input files. You can implement multiple file layouts only with fixed format files.

Example

&RECSTRING = &MYFILE.CurrentRecord;

File class: SetFileId method, ReadRowset method, IsNewFileId property.

Multiple File Layouts

#### IgnoreInvalidId

Description

This property is a file layout property that’s used in combination with the ReadRowset method. It returns a Boolean value that specifies whether file records with invalid FileIds are ignored. Each time ReadRowset is executed, it may encounter a file record that doesn't qualify as part of the rowset because its File ID isn’t part of the current file layout, or because it occurs in an invalid position in the rowset. If IgnoreInvalidId is False, the PeopleCode program terminates; if IgnoreInvalidId is True, ReadRowset ignores the invalid file record. The default value is True.

Example

&MYFILE.IgnoreInvalidId = False;

#### IsError

Description

This property is a file layout property. It returns a Boolean value indicating whether a field error condition was generated by the last file layout method executed. If an error condition was generated, IsError returns True; if not, IsError returns False. The default value is False.

Example

The following example shows where IsError would be used:

&MYFILE.Open(&SOMENAME, "R");
&MYFILE.SetFileLayout(FILELAYOUT.SOMELAYOUT);
If &MYFILE.IsError Then
/* Examine the EditError property of each field in the rowset
to find the one with the error, and respond accordingly */
End-If;
&MYFILE.Close();

Multiple File Layouts.

#### IsNewFileId

Description

This property is a file layout property. It returns a Boolean value indicating whether a FileId file record has been encountered. When the ReadRowset method reads a transaction from an input file, it examines the current file record following the transaction. If that file record is a FileId file record, IsNewFileId returns True; if not, IsNewFileId returns False.

IsNewFileId is used in combination with the SetFileId method and CurrentRecord property when reading files that require multiple file layouts.

Note. SetFileId, CurrentRecord, and IsNewFileId don’t apply to CSV and XML format input files. You can use only fixed format files to implement multiple file layouts.

Example

&MYFILE.SetFileLayout(FILELAYOUT.SOMELAYOUT) then  /* Set the first layout */
&MYFILE.SetFileId("999", 1);  /* Set the FileId */
While &SOMEROWSET <> NULL
If &MYFILE.IsNewFileId Then
/* Examine &MYFILE.CurrentRecord for the next layout */
/* Set the next layout */
&MYFILE.SetFileId("999", 1);  /* Set the FileId */
End-If;
/* Process the current &SOMEROWSET */
End-While;

File class: ReadRowset method, SetFileId method, CurrentRecord property.

#### IsOpen

Description

This property returns a Boolean value indicating whether the file is open. If the file object is open, IsOpen returns True; if not, IsOpen returns False.

Example

The following example opens a file, writes a line to it, and closes it:

&MYFILE.Open("item.txt", "W");
If &MYFILE.IsOpen Then
&MYFILE.WriteLine("Some text.");
&MYFILE.Close();
End-If;

#### Name

Description

This property returns as a string the name of the external file. If no file is currently associated with the file object, Name returns a NULL string.

Example

&TMP = &MYFILE.Name;

#### TerminateLines

Description

Use the TerminateLines property to indicate whether all output data lines are to be terminated at the end of the defined data length. This property is a file layout property associated with fixed file layouts only.

This property takes a Boolean value: True to force output data lines to be terminated at the end of the defined data length; False to keep all lines all at the maximum of their own length or that of their children. The default value is false.

Example

If &FILE_CREATED = "N" Then
&FILE_CREATED = "Y";
&FILENAME = &MSGNAME | "_" | &PROCESS_INSTANCE | "_*.out";
&FILE = GetFile(&FILENAME, "N", "U");
&FILE.SetFileLayout(@("FILELAYOUT." | &MSGNAME));
&FILE.TerminateLines = True;
&RS_LVL0 = &FILE.CreateRowset();
&REC_MSG_LVL0 = &RS_LVL0(&ROWCNT0).GetRecord(1);

If EO_BATLIB_AET.CREATE_FILE_FLG = "C" Then
&STRING = "998       " | &MSGNAME;
&FILE.WriteLine(&STRING);
End-If;
End-If;


#### UseSpaceForNull

Description

Use the UseSpaceForNull property to specify whether the WriteRowset method writes <qualifier> <qualifier> (<qualifier>-space-<qualifier>) for all the Null or empty character fields of a CSV-type file layout, or if the method writes <qualifier><qualifier> (<qualifier>-<qualifier>).

This property takes a Boolean value: false if WriteRowset writes <qualifier>-<qualifier>, true if WriteRowset writes <qualifier>-space-<qualifier>. The default is False.

Note. The state of this property has no effect on the behavior of the ReadRowset method. It also has no effect when the associated file layout is of type fixed or XML.

Example

Local File &LOGFILE;
Local File &FILE1;
Local File &FILE2;
Local Record &REC1;
Local SQL &SQL1;
Local Rowset &RS1;
Local Row &ROW1;

&LOGFILE = GetFile("C:\Temp\currency.log", "W", "A", %FilePath_Absolute);
If (&LOGFILE = Null) Then
Exit;
End-If;
If Not (&LOGFILE.SetFileLayout(FileLayout.CURRENCY_FL)) Then
&LOGFILE.WriteLine("SetFileLayout() on LOGFILE failed.");
End-If;

&FILE1 = GetFile("C:\Temp\currency_nonspaced.csv", "W", "A", %FilePath_Absolute);
If (&FILE1 = Null) Then
&LOGFILE.WriteLine("FATAL ERROR:  GetFile() on non-spaced output file failed.");
&LOGFILE.Close();
Exit;
End-If;
If Not (&FILE1.SetFileLayout(FileLayout.CURRENCY_FL)) Then
&LOGFILE.WriteLine("FATAL ERROR:  SetFileLayout() on non-spaced output file⇒
failed.");
&LOGFILE.Close();
&FILE1.Close();
Exit;
End-If;

&FILE2 = GetFile("C:\Temp\currency_spaced.csv", "W", "A", %FilePath_Absolute);
If (&FILE2 = Null) Then
&LOGFILE.WriteLine("FATAL ERROR:  GetFile() on spaced output file failed.");
&LOGFILE.Close();
&FILE1.Close();
Exit;
End-If;
If Not (&FILE2.SetFileLayout(FileLayout.CURRENCY_FL)) Then
&LOGFILE.WriteLine("FATAL ERROR:  SetFileLayout() on spaced output file⇒
failed.");
&LOGFILE.Close();
&FILE1.Close();
&FILE2.Close();
Exit;
End-If;

&REC1 = CreateRecord(Record.CURRENCY_CD_TBL);
If (&REC1 = Null) Then
&LOGFILE.WriteLine("FATAL ERROR:  CreateRecord() on record failed.");
&LOGFILE.Close();
&FILE1.Close();
&FILE2.Close();
Exit;
End-If;

&RS1 = CreateRowset(Record.CURRENCY_CD_TBL);
If (&RS1 = Null) Then
&LOGFILE.WriteLine("FATAL ERROR:  CreateRowset() on record failed.");
&LOGFILE.Close();
&FILE1.Close();
&FILE2.Close();
Exit;
End-If;

&SQL1 = CreateSQL("%Selectall(:1)", &REC1);
If (&SQL1 = Null) Then
&LOGFILE.WriteLine("FATAL ERROR:  CreateSQL() failed.");
&LOGFILE.Close();
&FILE1.Close();
&FILE2.Close();
Exit;
End-If;

If (&FILE1.UseSpaceForNull) Then
&LOGFILE.WriteLine("UseSpaceForNull is True on non-spaced output, by default.");
Else
&LOGFILE.WriteLine("UseSpaceForNull is False on non-spaced output, by⇒
default.");
End-If;
If (&FILE2.UseSpaceForNull) Then
&LOGFILE.WriteLine("UseSpaceForNull is True on spaced output, by default.");
Else
&LOGFILE.WriteLine("UseSpaceForNull is False on spaced output, by default.");
End-If;

&FILE1.UseSpaceForNull = True;
If (&FILE1.UseSpaceForNull) Then
&LOGFILE.WriteLine("Setting UseSpaceForNull to True succeeded on non-spaced⇒
output.");
Else
&LOGFILE.WriteLine("Setting UseSpaceForNull to True failed on non-spaced⇒
output.");
End-If;
&FILE2.UseSpaceForNull = True;
If (&FILE2.UseSpaceForNull) Then
&LOGFILE.WriteLine("Setting UseSpaceForNull to True succeeded on spaced⇒
output.");
Else
&LOGFILE.WriteLine("Setting UseSpaceForNull to True failed on spaced output.");
End-If;

&FILE1.UseSpaceForNull = False;
If (&FILE1.UseSpaceForNull) Then
&LOGFILE.WriteLine("Setting UseSpaceForNull to False failed on non-spaced⇒
output.");
Else
&LOGFILE.WriteLine("Setting UseSpaceForNull to False succeeded on non-spaced⇒
output.");
End-If;
&FILE2.UseSpaceForNull = False;
If (&FILE2.UseSpaceForNull) Then
&LOGFILE.WriteLine("Setting UseSpaceForNull to False failed on spaced output.");
Else
&LOGFILE.WriteLine("Setting UseSpaceForNull to False succeeded on spaced⇒
output.");
End-If;

&FILE1.UseSpaceForNull = False;
&FILE2.UseSpaceForNull = True;
&I = 1;
While &SQL1.Fetch(&REC1)
&ROW1 = &RS1.GetRow(1);
&REC1.CopyFieldsTo(&ROW1.CURRENCY_CD_TBL);
&FILE1.WriteRowset(&RS1, True);
&FILE2.WriteRowset(&RS1, True);
REM   &LOGFILE.WriteLine("Got row " | String(&I));
&I = &I + 1;
End-While;

&FILE1.Close();
&FILE2.Close();
&LOGFILE.Close();



WriteRowset

#### ZeroExtend

Description

Use this property to specify whether or not the WriteRowset method zero-extends the value it writes for decimal fields for CSV or XML format files.

For example, for a decimal field defined as 6.3, the value 1.12 will be written as follows depending on the value of ZeroExtend:

True: 1.120

False: 1.12

This property takes a Boolean value: true if WriteRowset zero-extends the value it writes; false otherwise. The default value is true.

Note. This property has no effect in the case of a fixed-position format file. In addition, it does not affect the behavior of the ReadRowset method.

File class: WriteRowset method.

### File Layout Examples

If your data is hierarchical in nature, or based on existing PeopleSoft records or pages, you want to use a File Layout definition for reading and writing your data, rather than doing it line by line (or field by field.)

For example, suppose you wanted to write all the information from a record to a file. You can use the WriteRecord method to write all the data from the record, instead of having to loop through every field, find the value, and write it to the file.

In addition, you could write all the information from a transaction (or several transactions) from a page to a file. Each transaction can be considered a rowset. A rowset can contain more than one record and is generally composed in a hierarchical structure. You could create a File Layout definition that has the same structure as the page (or component), and use the WriteRowset method. If you have a file that contains data in the correct format, you can use the ReadRowset method to read the data from the file to the page.

Each file layout is associated with a format. This format specifies the type of data in the files. You specify the format as part of the File Layout Properties. You can only specify one format for a file layout. Available formats are:

• FIXED (default)

• CSV

• XML

The file layout methods and properties use this information to handle each file type in a transparent manner. Generally, you don’t need to do anything different based on file type. Any exceptions are noted in the documentation.

Note. Unlike other PeopleTools definitions, records and field are copied to a File Layout definition. There are no pointers. This means if you change a record definition (add or remove a field) you must change the File Layout definition also. The changes are not automatically propagated. This is why the documentation refers to these elements as file records, file fields, and so on, to show that they are no longer part of the original definition they were created from.

PeopleSoft recommends regenerating all file layout definitions after any upgrade, to avoid any corruption caused by changes to the database.

See Using Standalone Rowsets for more examples of writing from and reading to files using File Layout and standalone rowsets.

Using Standalone Rowsets

Accessing the Data Buffer

Constructing File Layouts and Performing Data Interchanges

#### WriteRecord Example

In the following example, the File Layout definition is based on the record ABSENCE_HISTORY, and looks like this:

Example File Layout definition (ABS_HIST)

You should note the following about the using the WriteRecord method:

• Not all the fields in the File Layout definition and the record have to match. The WriteRecord method, like all File Layout methods, applies only to the like-named fields. If there are additional fields in the record or in the File Layout definition, they are ignored.

• The WriteRecord method writes only to like-named records. If you rename a record after you use it to create a File Layout definition, you must rename it to the exact same name in your File Layout. Because WriteRecord writes like-named records, the same file layout definition can contain more than one record.

• The WriteRecord method takes a record object as its parameter. A populated record object references a single row of data in the SQL table. This is why a SQL Fetch statement is used in a condition around the WriteRecord method. This fetches every row of data from the SQL table, then writes it to the file.

The following code writes the ABSENCE_HIST record to the file record.txt.

Local Record &RecLine;
Local File &MYFILE;
Local SQL &SQL2;

&MYFILE = GetFile("record.txt", "A");

If &MYFILE.IsOpen Then
If &MYFILE.SetFileLayout(FileLayout.ABS_HIST) Then
&RecLine = CreateRecord(RECORD.ABSENCE_HIST);
&SQL2 = CreateSQL("%Selectall(:1)", &RecLine);
While &SQL2.Fetch(&RecLine)
&MYFILE.WriteRecord(&RecLine);
End-While;
Else
/* do error processing -; filelayout not correct */
End-If;
Else
/* do error processing -; file not open */
End-If;

&MYFILE.Close();

If you wanted to write only changed records to the file, you could add the following code that is set in bold font:

While &SQL2.Fetch(&RecLine)
​If &RecLine.IsChanged Then
​&MYFILE.WriteRecord(&RecLine);
​End-If;
​End-While;

The following is the first part of a sample data file created by the previous code. The field format is FIXED:

8001       VAC 09/12/1981 09/26/1981 14  0                                  P Y
8001       VAC 03/02/1983 03/07/1983 5   0                                  P Y
8001       VAC 08/26/1983 09/10/1983 13  0                                  P Y
8105       CNF 02/02/1995 ??/??/     0   0                                  U N
8516       MAT 06/06/1986 08/01/1986 56  0                                  P Y
8516       SCK 08/06/1988 08/07/1988 1   0                                  P Y
8516       VAC 07/14/1987 07/28/1987 14  0                                  P Y
8553       JUR 12/12/1990 12/17/1990 5   0   Local Jury Duty                P N
8553       MAT 02/20/1992 10/01/1992 224 0   Maternity Leave                U N
8553       MAT 08/19/1994 03/01/1995 194 0   Maternity-2nd child            U Y
8553       PER 04/15/1993 04/19/1993 4   0                                  U N⇒
Personal Day required
8553       SCK 01/28/1987 01/30/1987 2   0   Hong Kong Flu                  P N
8553       SCK 08/02/1988 08/03/1988 1   0   Sick                           P N
8553       SCK 09/12/1995 09/13/1995 1   0                                  P N
8641       VAC 06/01/1988 06/15/1988 14  0                                  P Y
8641       VAC 07/01/1989 07/15/1989 14  0                                  P Y
G001       MAT 07/02/1991 09/28/1991 88  0   3-month Maternity leave        P Y⇒
Maternity will be paid as 80% of Claudia's current salary.                      

If a record in the File Layout definition has a File Record ID, each line in the file referencing this record is prefaced with this number. The File Record ID is not a field in the data itself. It is also referred to as the rowid. File Record IDs can be useful when the file you’re producing refers to more than one record.

File Record IDs can be used only with File Layout definitions that have a type of FIXED. If a File Layout definition has only one level then File Record IDs can be omitted. But for File Layout definitions with more than one level, you must use File Record IDs.

The following is sample file, produced with the same code, but with a File Record ID of 101 added:

101 8001       VAC 09/12/1981 09/26/1981 14  0                              P Y
101 8001       VAC 03/02/1983 03/07/1983 5   0                              P Y
101 8001       VAC 08/26/1983 09/10/1983 13  0                              P Y
101 8105       CNF 02/02/1995 ??/??/     0   0                              U N
101 8516       MAT 06/06/1986 08/01/1986 56  0                              P Y
101 8516       SCK 08/06/1988 08/07/1988 1   0                              P Y
101 8516       VAC 07/14/1987 07/28/1987 14  0                              P Y
101 8553       JUR 12/12/1990 12/17/1990 5   0   Local Jury Duty            P N
101 8553       MAT 02/20/1992 10/01/1992 224 0   Maternity Leave            U N
101 8553       MAT 08/19/1994 03/01/1995 194 0   Maternity-2nd child        U Y
101 8553       PER 04/15/1993 04/19/1993 4   0                              U N⇒
Personal Day required
101 8553       SCK 01/28/1987 01/30/1987 2   0   Hong Kong Flu              P N
101 8553       SCK 08/02/1988 08/03/1988 1   0   Sick                       P N
101 8553       SCK 09/12/1995 09/13/1995 1   0                              P N
101 8641       VAC 06/01/1988 06/15/1988 14  0                              P Y
101 8641       VAC 07/01/1989 07/15/1989 14  0                              P Y
101 G001       MAT 07/02/1991 09/28/1991 88  0   3-month Maternity leave    P Y⇒
Maternity will be paid as 80% of Claudia's current salary.                      

Note. File positions start at 1, not 0. When you specify a File Record ID, make sure that the starting position of the Record ID is greater than 0.

This following example uses the same File Layout definition as the previous example. The file format is CSV. The fields are separated by commas and delimited by double-quotes.

"8001","VAC","09/12/1981","09/26/1981","14","0","","P","Y",""
"8001","VAC","03/02/1983","03/07/1983","5","0","","P","Y",""
"8001","VAC","08/26/1983","09/10/1983","13","0","","P","Y",""
"8105","CNF","02/02/1995","??/??/","0","0","","U","N",""
"8516","MAT","06/06/1986","08/01/1986","56","0","","P","Y",""
"8516","SCK","08/06/1988","08/07/1988","1","0","","P","Y",""
"8516","VAC","07/14/1987","07/28/1987","14","0","","P","Y",""
"8553","JUR","12/12/1990","12/17/1990","5","0","Local Jury Duty","P","N",""
"8553","MAT","02/20/1992","10/01/1992","224","0","Maternity Leave","U","N",""
"8553","MAT","08/19/1994","03/01/1995","194","0","Maternity-2nd child","U","Y",""
"8553","PER","04/15/1993","04/19/1993","4","0","","U","N","Personal Day required"
"8553","SCK","01/28/1987","01/30/1987","2","0","Hong Kong Flu","P","N",""
"8553","SCK","08/02/1988","08/03/1988","1","0","Sick","P","N",""
"8553","SCK","09/12/1995","09/13/1995","1","0","","P","N",""
"8641","VAC","06/01/1988","06/15/1988","14","0","","P","Y",""
"8641","VAC","07/01/1989","07/15/1989","14","0","","P","Y",""
"G001","MAT","07/02/1991","09/28/1991","88","0","3-month Maternity leave","P","Y",⇒
"Maternity will be paid as 80% of Claudia's current salary."

To read in the previous CSV file we use the following PeopleCode. It reads the file into a temporary record. First each line of the file is read into a string. The string is split into an array, with the value of each field in the array becoming an element in the array. The value of each field in the record is assigned a value from the array. After additional processing (for example, converting strings into dates or numbers, verifying data, and so on) the record can be inserted into the database. To insert the final data into the database, this code must be associated with a PeopleCode event that allows database updates, that is, SavePreChange, WorkFlow, SavePostChange, and so on. This code could also be used as part of an Application Engine program.

Local File &MYFILE;
Local Record &REC;
Local array of string &ARRAY;

&MYFILE = GetFile("c:\temp\vendor.txt", "R", %FilePath_Absolute);
&REC = CreateRecord(RECORD.ABS_HIST_TEST);
&ARRAY = CreateArrayRept("", 0);

If &MYFILE.IsOpen Then
If &MYFILE.SetFileLayout(FILELAYOUT.ABS_HIST) Then
&ARRAY = Split(&STRING, ",");
For &I = 1 To &REC.FieldCount
&REC.GetField(&I).Value = &ARRAY[&I];
End-For;
/* do additional processing here for converting values */
&REC.Insert();
End-While;
Else
/* do error processing - filelayout not correct */
End-If;
Else
/* do error processing - file not open */
End-If;

&MYFILE.Close();

Note. You can't read a file that contains a thousands separator for numeric fields. You must strip out the separator before you try to read in the file.

#### WriteRowset Example

In the following example, the File Layout definition is based on the component EMPL_CHECKLIST, and looks like this:

Example File Layout definition (EMPL_CHECKLIST)

Here’s the structure of the component EMPLOYEE_CHECKLIST:

EMPLOYEE_CHECKLIST Component structure

Note that:

• Every field in the two structures don’t have to match (that is, every field or record that’s in the file layout doesn’t have to be in the component, and vice versa.)

• The two structures must be the same. That is, if the component has PERSONAL_DATA at level zero, and EMPL_CHECKLIST at level one, the file layout must have the same hierarchy.

The following example uses the previous File Layout definition to copy data from the EMPL_CHECKLIST page into a file.

The CreateRowset function creates an empty rowset that has the structure of the file layout definition. The GetRowset function is used to get all the data from the component and copy it into the rowset. The GetLevel0 function copies all like-named fields to like-named records. The WriteRowset method writes all the component data to the file. Because this code runs on the server, an absolute file path is used.

See GetRowset.

Example

The following is the PeopleCode for this example.

Local File &MYFILE;
Local Rowset &FILEROWSET;

&MYFILE = GetFile("c:\temp\EMP_CKLS.txt", "A", %FilePath_Absolute);
If &MYFILE.IsOpen Then
If &MYFILE.SetFileLayout(FILELAYOUT.EMPL_CHECKLIST) Then
&FILEROWSET = &MYFILE.CreateRowset();
&FILEROWSET = GetLevel0();
&MYFILE.WriteRowset(&FILEROWSET, True);
Else
End-If;
Else
/* file not opened, do error processing */
End-if;

&MYFILE.Close();

The following is a sample data file created by the previous code:

8113       Frumman,Wolfgang
08/06/1999 000001           8219        Going to London office
100     000015 I 08/06/1999
200     000030 I 08/06/1999
300     000009 I 08/06/1999
400     000001 I 08/06/1999
500     000011 I 08/06/1999
600     000002 I 08/06/1999
700     000021 I 08/06/1999
800     000024 I 08/06/1999
900     000004 I 08/06/1999
1000    000006 I 08/06/1999
09/06/1999 000004           7707        What to do after he arrives
100     000022 I 08/06/1999
200     000008 I 08/06/1999
300     000018 I 08/06/1999
400     000019 I 08/06/1999
8101       Penrose,Steven
07/06/1999 000006           8229        New hire
1       000033 I 08/06/1999
2       000034 I 08/06/1999
3       000035 I 08/06/1999
4       000036 I 08/06/1999
5       000037 I 08/06/1999
6       000038 I 08/06/1999
7       000039 I 08/06/1999
8       000040 I 08/06/1999
9       000041 I 08/06/1999
10      000042 I 08/06/1999 

When you create the File Layout definition, you can choose for each field whether to inherit a value from a higher level record field. If a value is inherited, it is written only once to the file, the first time it's encountered.

In the previous data example, there are three records: PERSONAL_DATA, EMPL_CHECKLIST, and EMPL_CHKLST_ITM. The field EMPLID is on all three records, but is written to the file only the first time a new value is encountered. So, the value for EMPLID is inherited by EMPL_CHECKLIST, and the value for EMPL_CHKLST_ITM is inherited from PERSONAL_DATA. The field CHECKLIST_DT is on EMPL_CHECKLIST and EMPL_CHKLST_ITM. However, the field value appears only once, in the parent record, and not in the child record.

If a record in the File Layout definition has a File Record ID, each line in the file referencing this record will be prefaced with this number. The File Record ID is not a field in the data itself. It is also referred to as the rowid. File Record IDs can be useful when the file being created refers to more than one record. File Record IDs can be used only with File Layout definitions that have a type of FIXED.

The following is sample file, produced with the same code, but with a File Record IDs added to all the records. 001 was added to the first level, 002 to the second, and 003 to the third.

001 8113       Frumman,Wolfgang
002            08/06/1999      000001 8219        Going to London office
003                       100    000015 I 10/13/1999
003                       200    000030 I 10/13/1999
003                       300    000009 I 10/13/1999
003                       400    000001 I 10/13/1999
003                       500    000011 I 10/13/1999
003                       600    000002 I 10/13/1999
003                       700    000021 I 10/13/1999
003                       800    000024 I 10/13/1999
003                       900    000004 I 10/13/1999
003                       1000   000006 I 10/13/1999
002            09/06/1999      000004 7707        What to do after he arrives
003                       100    000022 I 10/13/1999
003                       200    000008 I 10/13/1999
003                       300    000018 I 10/13/1999
003                       400    000019 I 10/13/1999
001 8101       Penrose,Steven
002            10/13/1999      000006 8229        New hire
003                       1      000033 I 10/13/1999
003                       2      000034 I 10/13/1999
003                       3      000035 I 10/13/1999
003                       4      000036 I 10/13/1999
003                       5      000037 I 10/13/1999
003                       6      000038 I 10/13/1999
003                       7      000039 I 10/13/1999
003                       8      000040 I 10/13/1999
003                       9      000041 I 10/13/1999
003                       10     000042 I 10/13/1999 

The following program reads all the rowsets from a file and updates a work scroll with that data. The work scroll isn’t hidden on the page: it’s created in the Component buffer from existing records using CreateRowset. The structure of the work scroll and the file layout are identical: that is, they’re composed of two records, and the names of the records in the file layout are exactly the same as the names of the record definitions.

Local File &CHARTINPUT_F;
Local Rowset &INPUT_ROWSET, &TEMP_RS, &WORK_DATA;
Local Record &WRK_DATA;

&filename = "c:\temp\test.txt";
If FileExists(&filename, %FilePath_Absolute) Then
&CHARTINPUT_F = GetFile(&filename, "R", "A", %FilePath_Absolute);
Else
Exit;
End-If;

&CHARTINPUT_F.SetFileLayout(FileLayout.CHART_INFO);

/* Create rowset to be read into
NOTE that you have to start at LOWEST level of rowset */

&TEMP_RS = CreateRowset(RECORD.CHART_ITEM);
&WORK_DATA = CreateRowset(RECORD.CHART_DATA, &TEMP_RS);
&INPUT_ROWSET = CreateRowset(RECORD.CHART, &WORK_DATA);

While &INPUT_ROWSET <> Null
&INPUT_ROWSET.CopyTo(&WORK_DATA);
/* do processing -- Though file may contain more than one level zero
Component processor only allows one level zero at a time */
End-While;

#### File Rowset Considerations

The following are considerations for when you use rowsets with files.

• Although you can create a File Layout definition with more than four levels of hierarchy, a rowset created from Component buffer data can contain only four levels (level zero through 3). Any additional levels of data are ignored.

• ReadRowset populates the rowset with one transaction from the file. (A transaction is considered to be one instance of level zero data contained in a file record, plus all of its subordinate data.) WriteRowset writes one transaction to a file.

#### Application Engine Example

You can also use PeopleCode in an Application Engine program to either write to or read from files. This example isn't a proper Application Engine program: it contains the PeopleCode only for opening and reading from a file. However, it's included here as starting point for your own Application Engine programs.

Here is the Application Engine program:

Application Engine example program

Here is the PeopleCode in the step 1.

Local File &FILE;
Local Record &REC;
Local Rowset &FRS;

&FILE = GetFile("TEST.txt", "R");
&REC = CreateRecord(Record.QEPC_FILE_REC);
&SQL = CreateSQL("%Insert(:1)");

If Not &FILE.IsOpen Then
Error ("TEST: failed file open");
Else
If Not &FILE.SetFileLayout(FileLayout.QEPC_FILE_REC) Then
Error ("TEST: failed SetFilelayout");
Else
While &FRS <> Null
&FRS.GetRow(1).QEPC_FILE_REC.CopyFieldsTo(&REC);
&SQL.execute(&REC);
End-While;
End-If;
&FILE.Close();
End-If;

The example Application Engine program reads the following CSV file:

"TEST2","1ST","01/01/1901",10
"TEST2","2ND","01/01/1902",20
"TEST2","3RD","01/01/1903",30
"TEST2","4TH","01/01/1904",40

Note that the last field has no qualifier.

The File Layout used to read this record has the following form:

QEPC_FILE_REC File Layout

The properties for the QEPC_FILE_REC File Layout are as follows:

File Layout Definition Properties

Note that the Definition Qualifier is double-quotes ("), while the separator is a comma.

Remember, the last field didn't have a qualifier. To account for that, the field properties for this field must be edited, and a blank must be put in the Field Qualifier property.

File layout Field Properties

See Understanding Application Engine.

### Multiple File Layouts

In the previous examples, the input file contained rowsets based on a single File Layout definition. However, PeopleTools provides the functionality to process input files containing rowsets that require several different File Layouts.

Note. You can use only fixed format files to implement multiple file layouts.

See the SetFileId method for details about handling multiple file layouts.

In this section, we discuss how to:

• Write multiple file layouts.

See File class: SetFileId method.

If your input file contains data based on more than one File Layout, it must contain an indicator, called a FileId that specifies:

• When a different File Layout definition should be used.

• Which File Layout definition should be used.

The FileId must be specified on a separate line and must precede every rowset that requires a layout different from the previous rowset. It isn’t considered part of the rowset.

In the following example, the file contains two FileId lines; they use a file record ID that distinguishes them from the rowset data—in this case, "999".

999 PRODUCT  ​/* The following rowset uses the PRODUCT layout */
​001  ​/* Level 0 record data */
​101  ​/* level 1 record data */
​201  ​/* Level 2 record data */
​201  ​/* Level 2 record data */
​999 ORDER  ​/* The following two rowsets use the ORDER layout */
​001  ​/* Level 0 record data */
​111  ​/* Level 1 record data */
​111  ​/* Level 1 record data */
​001  ​/* Level 0 record data */
​111  ​/* Level 1 record data */
​111  ​/* Level 1 record data */

The FileId can contain any information you want that indicates which file layout to use; the "PRODUCT" and "ORDER" fields shown are just examples.

To read this file, you should do the following in your program:

1. Use the SetFileId method to specify the file record ID value.

3. Check if the rowset is NULL.

NULL indicates you’ve reached either the end of the file or a new rowset.

4. Use the IsNewFileId property to check if the next line is a FileId file record (line).

• If IsNewFileld is False, you’ve reached the end of the file.

• If IsNewFileld is True, use the CurrentRecord property to determine which File Layout to use next.

The following example reads rowsets from a file. When it finds a new rowset (indicated by &IsNewFileld returning True) the value of &CurrentRecord is passed to a function that reads and evaluates the line, then returns the name of the new file layout. (The code for the function FindFileId is included at the start of the example.)

Local File &MYFILE;
Local Rowset &rsFile;
Local Record &rSomeRec1, &rSomeRec2;
Local SQL &SQL1;

Function FindFileID(&CurrentRecord As string) Returns string ;
Evaluate RTrim(Substring(&CurrentRecord, 5, 50))
When "SOME_REC1"
&FILELAYOUT = "SOME_REC1";
When "SOME_REC2"
&FILELAYOUT = "SOME_REC2";
End-Evaluate;
Return &FILELAYOUT;
End-Function;

&rSomeRec1 = CreateRecord(Record.SOME_REC1);
&rSomeRec2 = CreateRecord(Record.SOME_REC2);
&SQL1 = CreateSQL("%Insert(:1)");
&MYFILE = GetFile("c:\temp\MULTI_FILE.out", "R", %FilePath_Absolute);

rem Set temporary first file layout;
&MYFILE.SetFileLayout(FileLayout.SOME_REC1);
&MYFILE.SetFileId("999", 1);

rem Read rowset to find actual first file ID;
&CurrentRecord = &MYFILE.CurrentRecord;
&IsNewFileID = &MYFILE.IsNewFileId;
If &MYFILE.IsNewFileId Then
&FILELAYOUT = FindFileID(&CurrentRecord);
&MYFILE.SetFileLayout(@("FileLayout." | &FILELAYOUT));
&MYFILE.SetFileId("999", 1);
End-If;

&CurrentRecord = &MYFILE.CurrentRecord;
&IsNewFileID = &MYFILE.IsNewFileId;
While &rsFile <> Null Or
&IsNewFileID
If &MYFILE.IsNewFileId Then
&FILELAYOUT = FindFileID(&CurrentRecord);
&MYFILE.SetFileLayout(@("FileLayout." | &FILELAYOUT));
&MYFILE.SetFileId("999", 1);
If &IsNewFileID Then
&CurrentRecord = &MYFILE.CurrentRecord;
&IsNewFileID = &MYFILE.IsNewFileId;
End-If;
End-If;

Evaluate &FILELAYOUT

When "SOME_REC1"
&rsFile(1).SOME_REC1.CopyFieldsTo(&rSomeRec1);
&rSomeRec1.ExecuteEdits(%Edit_Required);
If Not &rSomeRec1.IsEditError Then
&SQL1.Execute(&rSomeRec1);
End-If;
Break;
When "SOME_REC2"
&rsFile(1).SOME_REC2.CopyFieldsTo(&rSomeRec2);
&rSomeRec2.ExecuteEdits(%Edit_Required);
If Not &rSomeRec2.IsEditError Then
&SQL1.Execute(&rSomeRec2);
End-If;
End-Evaluate;

&CurrentRecord = &MYFILE.CurrentRecord;
&IsNewFileID = &MYFILE.IsNewFileId;
End-While;

&MYFILE.Close();

See File class: SetFileId method, ReadRowset method, IsNewFileId property.

#### Writing Multiple File Layouts

If you’re writing files that contain data based on more than one File Layout definition, consider the following points:

• If the file is going to a third-party vendor, you should work with the third-party to determine what their requirements are for specifying the different data formats.

• If the file is going to be used by another PeopleSoft system, you must add the FileId between each rowset that requires a different layout. FileId file records are not part of any rowset. They should be designed so they won’t be mistaken for part of a rowset. You can create and write them to the file in many ways. The following are suggestions:

• Build each line as a string, using any of the built-in string manipulation functions, then write them to the file using the File class WriteLine or WriteString methods.

• Design a file layout consisting of a single file record definition for the FileId file records, then build the records using Record Class methods and functions, and write them to the file using the WriteRecord method.

The following code example writes each record from the level one scroll on a page to the file using a different File Layout. Between each WriteRowset the File ID file record is written to the file, describing the new File Layout being used.

Local File &MYFILE;
Local Rowset &FILEROWSET;
Local Record &REC1, &REC2;
Local SQL &SQL;

&MYFILE = GetFile("c:\temp\Records.txt", "W", %FilePath_Absolute);
If &MYFILE.IsOpen Then
If &MYFILE.SetFileLayout(FileLayout.TREE_LEVEL) Then
&REC1 = CreateRecord(Record.PSTREELEVEL);
&FILEROWSET = &MYFILE.CreateRowset();
&SQL = CreateSQL("%Selectall(:1)", &REC1);
/* write first File ID to file */
&MYFILE.WriteLine("999 FILE LAYOUT 1");
While &SQL.Fetch(&REC1)
&REC1.CopyFieldsTo(&FILEROWSET.GetRow(1).PSTREELEVEL);
&MYFILE.WriteRowset(&FILEROWSET, True);
End-While;
Else
End-If;

If &MYFILE.SetFileLayout(FileLayout.TREE_USERLEVEL) Then
&REC2 = CreateRecord(Record.TREE_LEVEL_TBL);
&FILEROWSET = &MYFILE.CreateRowset();
&SQL = CreateSQL("%Selectall(:1)", &REC2);
/* write second File ID to file */
&MYFILE.WriteLine("999 FILE LAYOUT 2");
While &SQL.Fetch(&REC2)
&REC2.CopyFieldsTo(&FILEROWSET.GetRow(1).TREE_LEVEL_TBL);
&MYFILE.WriteRowset(&FILEROWSET);
End-While;
Else
End-If;
Else
/* file not opened, do error processing */
End-If;
&MYFILE.Close();

See File class: WriteLine method, WriteString method, WriteRecord method.

See Record Class.