PeopleCode | Using native functions to interact with the file server
A. PeopleCode File Functions
PeopleCode is fairly limited when it comes to native functions that help you interact with the file server. Fortunately, a PeopleCode function library exists that provides a wider range of functionality. Even more fortunately, you are not limited to PeopleCode functions alone. You can also take advantage of Java file functionality within a PeopleCode programme. We’ll explore the power of Java in a separate post (Tip 050), but for now, we limit ourselves to the file functionality that exists within PeopleSoft.
Many of these functions ask that you specify the manner in which the file will be located. Are you supplying a full directory path or are you only supplying a file name and asking the system to use its ‘current’ directory? In the first case you will need to use an absolute file path (‘%FilePath_Absolute’), while in the second case, you will use a relative file path (‘%FilePath_Relative’). Refer to Tip 011 for more details on the ‘current working directory’.
This command is used to check whether a specific file exists in the file directory. It might be used when you’re about to create a file, but you want to first verify that a file of the same name doesn’t already exist.
Here’s an example of ‘FileExists’ using a relative file-path:
Local String &file_name = "PROCESS.log"; If FileExists(&file_name, %FilePath_Relative) Then /* File exists */ Else /* File does not exist */ End-If;
Here’s an example of ‘FileExists’ using an absolute file-path:
Local string &file_path = "/u02/psft/ps_cfg/appserv/PSDEV/LOGS/PS.log"; If FileExists(&file_path, %FilePath_Absolute) Then /* File exists */ Else /* File does not exist */ End-If;
Of course, the above example is clearly impractical for any PeopleSoft installation with multiple databases. The name of the database (PSDEV) has been hard-coded into the complete file path. Therefore, a better approach would be:
Local string &file_path = GetCwd() | "/LOGS/PS.log"; If FileExists(&file_path, %FilePath_Absolute) Then /* File exists */ Else /* File does not exist */ End-If;
Note that ‘FileExists’ does not handle pattern matching. Fortunately, there is a workaround.
‘FindFiles’ allows you to search a directory path for a particular file match. Unlike ‘FileExists’, the ‘FindFiles’ function does allow you to perform pattern matching, such as using ‘*’ for ‘any number of characters’. The results of the file match are stored in an array, so this must be defined in advance (as an array of string) and then passed into the ‘FindFiles’ function.
When calling the function you must also specify whether the search is performed on ‘%FilePath_Absolute’ or ‘%FilePath_Relative’. In this case, the search results differ depending on which option you select. For ‘Absolute’, you will receive the full file path and name for all matching files. For ‘Relative’, you will only receive the file name in return.
Here’s an example of using ‘FindFiles’ with %FilePath_Absolute:
Local array of string &matches; Local string &next_file, &file_search; Local integer &i; /* Search for file names containing the word INSTRUCTOR */ &file_search = GetCwd() | "/files/*INSTRUCTOR*"; &matches = FindFiles(&file_search, %FilePath_Absolute); /* Loop through each file match */ For &i = 1 To &matches.Len &next_file = &matches [&i]; /* Continue processing this file */ End-For;
As a reminder, the ‘&next_file’ variable in this example will be set to the file name AND file path, because we have specified an ‘absolute’ file path. Refer to section (4) below for details of some functions that can help to strip out the file name and file path.
Here’s an example of ‘FindFiles’ using relative file paths:
Local array of string &matches; Local string &next_file, &file_search; Local integer &i; &file_search = "*INSTRUCTOR*"; &matches = FindFiles(&file_search, %FilePath_Relative); /* Loop through each file match */ For &i = 1 To &matches.Len &next_file = &matches [&i]; /* Continue processing this file */ End-For;
In this case, ‘&next_file’ will only be set to the file name, with no complete path specified.
D. GetCWD and GetFile
‘GetCWD’ and ‘GetFile’ have already been discussed in other posts (Tip 011 and Tip014 respectively), so are only being mentioned now for the sake of completeness.
E. Functions from PSXPFUNCLIB
While there’s a smattering of other file related commands in the native PeopleCode language, these tend to be rarely used in practice. Therefore, to make up somewhat for the lack of functionality, a set of extended functions is available in the PSXPFUNCLIB record. This record also includes functions unrelated to file manipulation.
Here are some of the more useful file functions in PSXPFUNCLIB, with examples of each:
This deletes a file from the directory you specify. No return code is provided, so you do not know whether the delete was successful or not.
Declare Function DeleteLocalFile PeopleCode PSXPFUNCLIB.FUNCLIB FieldFormula; &file_name = GetCwd() | "/files/tmp.tmp"; DeleteLocalFile(&file_name, %FilePath_Absolute);
This deletes an entire directory. Again, no return code is provided by the function.
Declare Function DeleteLocalDirectory PeopleCode PSXPFUNCLIB.FUNCLIB FieldFormula; &file_path = GetCwd() | "/files/tmp"; DeleteLocalDirectory(&file_path, %FilePath_Absolute);
The separator character in a file path can differ depending on whether you’re on a UNIX based system (/) or whether you’re on a Windows system (\). Although some PeopleCode functionality will automatically convert the slashes for you if they happen to be incorrect, this is not a universal rule. To remove any doubt as to whether you’re using the correct type of slashes, consider the ‘GetDirSeparator’ function. This will set the file separator according to the current operating system.
Declare Function GetDirSeparator PeopleCode PSXPFUNCLIB.FUNCLIB FieldFormula; &file_path = GetCwd() | GetDirSeparator() | "files" | GetDirSeparator() | "tmp";
If you happen to have a full file path (directory path and file name), but are only interested in the file name, then the ‘GetFileNameFromPath’ function can help you out.
Declare Function GetFileNameFromPath PeopleCode PSXPFUNCLIB.FUNCLIB FieldFormula; Local array of string &matches; Local string &next_file, &file_search, &file_name; Local integer &i; &file_search = GetCwd() | "/files/FRED*.txt"; &matches = FindFiles(&file_search, %FilePath_Absolute); /* Loop through each file match */ For &i = 1 To &matches.Len &next_file = &matches [&i]; &file_name = GetFileNameFromPath(&next_file); End-For;
This is similar to ‘GetFileNameFromPath’ except it works in the opposite way. Now only the directory path text is returned by the function. The file name is removed.
Declare Function GetDirectoryFromPath PeopleCode PSXPFUNCLIB.FUNCLIB FieldFormula; &file_path = GetDirectoryFromPath(&next_file);
F. Exec Function
Before we wrap up, it’s worth briefly mentioning the PeopleCode ‘Exec’ function. This allows you to execute a line-level command at the operating system level. In theory then, you could use ‘Exec’ to ask the operating system to delete a file:
However, based on this example alone, you’ve probably already spotted one major problem with ‘Exec’. The contents of ‘Exec’ are highly dependent on the operating system. The ‘rm’ example was entered with UNIX in mind. This will not work on a Windows system.
Therefore, ‘Exec’ is being mentioned more as a last resort. If you have no luck performing your action by using any of the native or the Java functions, then you could always consider a command line script as a last resort, using the ‘Exec’ function. However, this tends to be a messy option, especially when you need to factor in multiple databases and servers (along with the support of a systems administrator or DBA). Always try to build a solution that use the PeopleCode constructs first, as opposed to relying on the fickle outside world.
Tip 011: Determine Current Working Directory
Tip 013: Using Arrays in PeopleCode
Tip 014: Creating a Custom Log File
Tip 035: Uploading a File Attachment
Tip 050: File Manipulation using Java Objects
Tip 060: Copying Files