Sat, Apr
5 New Articles

Reading IFS Files in RPG

  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Using RPG's traditional file input/output (I/O) operation codes to read files from the Integrated File System (IFS) is virtually impossible. The only way to do that today is to write a "driver" program that is used in conjunction with the SPECIAL device file. It would be beneficial to have integrated support for accessing all database systems and all file systems from within RPG, but we don't. So we have to make our own!

Fortunately, we can easily write the interfaces needed to access the IFS within RPG. Actually, although very little programming is required, there is a good bit of research required. But in the end, it works pretty well, so it's worth it.

It may seem as though the ongoing theme in several issues of Midrange Developer has been calling C language functions from within RPG IV. What is really happening is that IBM has exposed a number of APIs though the usual Qxxxxxx naming convention and also provided the C language with a callable function to do the same task (wrapping the API's complexities in some cases). Since the C language requires all functions to be callable via what's known as a "procedure pointer," IBM has had to externalize these C language functions. Therefore, it is often easier to call with the C language interface than the actual raw API itself. Remember, until Java came along, all the non-AS/400 programmers in the world were telling us how great C was and that it was the only language you need to use...so why not steal their functions and use them in good old RPG!

There are APIs, for example, that allow you to allocate memory dynamically while a program is running. In the C language, those APIs are wrapped by the C language runtime malloc(), realloc(), and free() functions. Until RPG IV recently added ALLOC, REALLOC, and DEALLOC to the language as native operation codes, you had a choice: call the OS/400 memory allocation APIs or call the much simpler C language functions.

The IFS is no different. The C language has a couple of options for accessing files stored in the IFS. You can open a file and read it in blocks--that is, read a specified number of bytes at a type. This is called byte I/O. You can also open an IFS file as a stream file, which is a different set of APIs, and use stream I/O to access the file. Stream I/O provides for record, or more accurately, line-at-a-time file access. You can read a line of a text file and write a line of a text file using stream I/O. If you use byte I/O, it is up to you to look at each input byte and decide what to do with it.

Normal IFS I/O (or byte I/O) has its advantages in that you can read both binary files, such as image files, and text files, such as HTML. Let's look at the APIs that support byte I/O first.

There are many file-oriented functions in the C language, but the I/O operations for the IFS include, but are not limited to, the following:

  • fclose()--Close file
  • feof()--Test for end-of-file indicator
  • ferror()--Test for read/write errors
  • fgetpos()--Get file position
  • fgets()--Read a string
  • fopen()--Open file
  • fputs()--Write string
  • fread()--Read a number of bytes from an IFS file
  • fseek()--Reposition file cursor
  • fsetpos()--Set file cursor
  • fwrite()--Write bytes to IFS file

These functions, like all C language functions, are case-sensitive. They are all lowercase names. They will not work if called as anything other than fully lowercase names.

Note that each function begins with the letter "f." This stands, appropriately enough, for "file." If you look at the C compiler, however, you'll find that the native versions of these interfaces do not access the IFS. In fact, the C language compiler directive IFCTRL(*IFSIO) needs to be specified in order to access the IFS natively. So an attempt to call these interfaces directly from RPG IV will fail.

As it turns out, the compiler actually uses a different set of APIs to access the IFS file system when IFCTRL(*IFSIO) is specified. Fortunately, since the compiler needs to change the actual names of the procedures being called, the C source code is provided. A quick review of the C "header files" (as they're called) reveals that all the interfaces are translated to API names that are similar to the original names with the addition of a "_C_IFS_" prefix. That is, they are named _C_IFS_xxxxx, where xxxxx is the original procedure name. So fopen() is translated to _C_IFS_fopen, again a case-sensitive name--uppercase for "_C_IFS_" and lowercase for "fopen." These are the procedure names we can call to get to the IFS from within RPG IV.

So, under the new naming convention, the proper IFS API names needed to access the IFS include the following:

  • _C_IFS_fclose()--Close file
  • _C_IFS_feof()--Test for end-of-file indicator
  • _C_IFS_ferror()--Test for read/write errors
  • _C_IFS_fgetpos()--Get file position
  • _C_IFS_fgets()--Read a string
  • _C_IFS_fopen()--Open file
  • _C_IFS_fputs()--Write string
  • _C_IFS_fread()--Read a number of bytes from an IFS file
  • _C_IFS_fseek()--Reposition file cursor
  • _C_IFS_fsetpos()--Set file cursor
  • _C_IFS_fwrite()--Write bytes to IFS file
  • _C_IFS_fdopen()--Associates a file handle with an IFS file
  • _C_IFS_fflush()--Flush out the write buffer to the file
  • _C_IFS_fgetc()--Read a character
  • _C_IFS_fileno()--Determine file handle associated with the IFS file
  • _C_IFS_fprintf()--Write formatted data to a file
  • _C_IFS_fputc()--Write a character
  • _C_IFS_freopen()--File redirector
  • _C_IFS_fscanf()--Read formatted data
  • _C_IFS_ftell()--Get current file cursor position

For a complete list of the IFS APIs, see the source file member named IFS in the source file named H in library QSYSINC: SRCFILE(QSYSINC/H) MBR(IFS)

I've selected a few of the IFS APIs for review here. These allow basic file open, close, read, write, delete end-of-file, and file positioning operations. Remember, IFS files are not DB2/400 database files, so the meaning of update and delete are different. With IFS files, there is no update operation--just a write operation that overwrites existing bytes in the file.

Let's look at a few of the IFS APIs and create prototypes so they may be called directly from within RPG IV.

FILE* _C_IFS_fopen(const char* filename, const char* mode);

The first parameter is the name of the file in the IFS that is to be open. The second parameter specifies the open options for the file, such as read/write/modify.

In RPG IV, use the VALUE keyword for these parameters rather than use the CONST keyword. VALUE provides results similar to CONST, but it allows you to avoid using the %ADDR built-in function.

     D ifsOpen         PR              *   ExtProc('_C_IFS_fopen')
     D  fileName                       *   Value Options(*STRING)
     D  filemode                       *   Value Options(*STRING)

Figure 1: The ifsOpen prototype

The first parameter is the name of the file to be open, but since it is a C null terminated string, it will require the file name to have a hex x (X'00') immediately after the last non-blank character in the file name. So passing a literal name, such as '/www/index.html' is perfectly valid, but passing the name of the file within a 50-position field would require the addition of the %TRIMR operation. For example, the following are valid IFSopen statements:

0001 D welcome         S            255a   INZ('/www/index.html')
0002 D pFile1          S               *   INZ
0003 C                   Eval      pFile1=fOpen(%TrimR(welcome) :'r'
0004 C                   Eval      pFile1=fOpen('/www/index.html':'r')

Figure 2: Use of ifsOpen with a field and a literal

Line 1 declares a 255-byte character field that contains the name of the file (including its directory) on the IFS. Line 3 opens that file. Note the use of %TRIMR to eliminate the trailing blanks from the name. It is important use %TRIMR; otherwise, the file name will not be found. RPG's OPTIONS(*STRING) causes the value being passed to be converted into a null-terminated string. It does this by passing the value to the called function as a 256-position value and inserting X'00' in that extra position. So OPTIONS(*STRING) increases the passed length by one byte and fills that one extra byte with a null value.

Line 2 declares a pointer variable. When the IFS APIs open a file, a pointer to the file is returned. That file pointer is used by (i.e., passed to) all other IFS APIs that access the same file. So the pointer variable is similar to the file name on a regular File Description specification.

Line 4 in Figure 2 uses a quoted literal instead of a field name to open the IFS file. Note that since a quoted character string is being used, no %TRIMR is required.

To open a file on the IFS for read-only, use the RPG prototype IFSopen with the name of the file as the first parameter and set the mode option (second parameter) to 'r'. Figure 3 contains a list of the available mode options and combinations. Note that all modes must be specified in lowercase.

Open Mode
Open a text file for reading. The file must exist.
Create a text file for writing. If the file exists, its contents are destroyed.
Open a text file for writing at the end of the file. If the file doesn't exist, it is created. Does not destroy file contents, but also does not move the end-of-file marker. Use 'a+' for most append operations.
Open a text file for reading and writing. The file must exist.
Open a text file for reading and writing. If the file exists, its contents are destroyed. That is, the file is cleared.
Open a text file for reading and appending; the appending operation includes the removal of the EOF marker before new data is written to the file, and the EOF marker is repositioned after writing is complete. If the file does not exist, it is created.
Open a binary file for reading. The file must exist.
Create an empty binary file for writing. If the file exists, its contents are cleared. That is, the file is virtually erased and recreated.
Open a binary file in append mode for writing at the end of the file. If the file doesn't exist, it is created.
r+b or rb+
Open a binary file for reading and writing. The file must exist.
w+b or wb+
Create an empty binary file for reading and writing. If the file exists, its contents are cleared. That is, the file is virtually erased and recreated.
a+b or ab+
Open a binary file in append mode for writing at the end of the file. If the file doesn't exist, it is created.

Figure 3: ifsOpen mode settings

As indicated in Figure 3, use a lowercase "r" to open files for read-only. Use "a+" to open files for reading and writing (input/output).

Once an IFS file is open, it can be read from or written to (depending on the mode options). As the file is being written to, the file's position is adjusted to point to the end-of-file so that you are always writing to the end of the IFS file. Use the ifsSeek API to position the file to any byte position in the file.

0001 D ifsReadLine     PR              *   ExtProc('_C_IFS_fgets')
0002 D  inBuffer                       *   Value Options(*STRING)
0003 D  inBufLen                     10I 0 Value
0004 D  stream_FILE                    *   Value

Figure 4: ifsReadLine--Read a "record" from an IFS text file

Line 1 in Figure 4 prototypes the IFS fgets() procedure. This procedure reads data from the IFS file up to a carriage return/line feed sequence, which effectively reads a line or record from an IFS text file. Using this method--as opposed to using some of the other APIs that are available--makes it much easier to read text-based IFS files.

You can easily prototype the other IFS procedures so that they can be called from RPG IV.

The IFS is becoming more and more important to the AS/400 programmer. Saving and retrieving both formatted and unformatted data, as well as reading data sent to your iSeries from non-iSeries systems, means IFS file access is here to stay.


Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.

MC Press books written by Robert Cozzi available now on the MC Press Bookstore.

Get this jam-packed resource of quick, easy-to-implement RPG tips!
List Price $65.00

Now On Sale

The Modern RPG IV Language The Modern RPG IV Language
Cozzi on everything RPG! What more could you want?
List Price $99.95

Now On Sale



Support MC Press Online

$0.00 Raised:

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: