Open worksofliam opened 5 years ago
dcl-pr OpenFile pointer extproc('_C_IFS_fopen');
*n pointer value; //File name
*n pointer value; //File mode
end-pr;
The resulting calls will be both simpler and look "more RPG like" if Options(*String) is added to the proto parameters and if the Pathfile variable etc. are changed to varchar. In fact I would normally coder the mode directly as shown below. The current calls would still be valid but a simplified version would also be available. e.g.
`dcl-pr OpenFile pointer extproc('_C_IFS_fopen');
*n pointer value options(*string); //File name
*n pointer value options(*string); //File mode
end-pr;
gStreamFile.PathFile = 'helloworld.txt';
gBuildFile.FilePtr = OpenFile( gBuildFile.PathFile )
: 'r' );
This option causes RPG to copy the supplied data to a temporary area and null terminate it for you. The result as I said is a far more RPG like call operation. It also calms the pointer-phobic!
Hi, What if I want to write the contents of a PF(physical file) having 100 fields, how do I do that. As I should write the 100 fields exclusively in the program. Please help.
Hi, What if I want to write the contents of a PF(physical file) having 100 fields, how do I do that. As I should write the 100 fields exclusively in the program. Please help.
You basically have a number of options.
1) Use CPYTOIMPF which gives you a CSV file with the contents.
2) Use a READ into a DS (externally described based on the file) and use the DS name as the source for the IFS write. This won't work well though if there are packed fields in the file. If there are you will need to build a logical over the file using zoned to redefine the packed fields and use that file as the data source.
3) Use a regular read and use %Char %Edit etc. to string out the record buffer in the layout you want.
This blog is a follow up from "A better way to read a file in the IFS with RPG" on RPGPGM.com. Writing to the IFS can be important. It can be really useful to store your own log files instead of writing to a physical file.. it may even be slightly easier. When I say file in this blog post, I mean IFS stream file - not physical file.
As a standard, I use this Template data structure for each IFS file I want to create or open in my file:
I define
PathFile
as aChar(128)
because I don't usually have paths that are more than 128 characters long.RtvData
should be the longest length of a line that you will find in any stream file that you open.OpenMode
requires a bit more knowlegde. There are different 'open codes' for different types of operations - such as reading, appending or overwrite. You can find a list of codes available on this MCPress article by Robert Cozzi (about half way down).Next you will want the four prototypes I use for all my code, which we will talk more about later.
I use
OpenMode = 'ab' + x'00'
to overwrite (or create) files and I useOpenMode = 'r' + x'00'
if I am purely reading a file. I am basing my code off two different sources file which are both open-source under the Relic Package Manager repository - they both use the data structure I declared at the top of this blog.Reading a file
This section of code comes from RELIC.SQLRPGLE. The logic of this code is to open a 'build file' and read through it's content. I firstly need to declare a new data structure over the template we created earlier.
Now we can store anything relevant to this specific file in this data structure, great! Next we need to put data into some of the sub-fields within our
gBuildFile
data structure.Now, you may be asking what
x'00'
is. As Simon says on his blog, he is null terminating the character fields. This basically tells the function where to stop reading. As a side note, if you don't explicitly specify the path of the file it will use your current directory. Like I mentioned earlier, I am usingr
for read mode on the file I have specified.What if the file didn't open? What if it didn't exist or some something stupid has happened and you can't open the file? We'd need to handle that of course. This simple if statement checks if the pointer to the file is
*null
, and if it is then it's not working.So it would only get past this point if the file has been opened correctly, which is what we want. Next, we can loop through our file and read the contents of it - using a do while! Nice and simple. So while
ReadFile
returns a pointer, it also passes in the lines value into one of the parameters by reference since we're passing it a pointer and length (gBuildFile.RtvData
)Before the end of the do-loop, it is vital we assign blank to
gBuildFile.RtvData
. If you don't characters will stick around in there when you read the next line. Since files can also contain weird things like line breaks, end of records, tabs, etc, we are going to need to remove those so we don't have anything icky in our program! After the beginning of the do-loop, you'll want these%xlate
s to replace those weird bytes.That's it. You can now read the clean data from your stream file in the IFS! The code might look something like this:
Writing a file
Writing a file has the same concept as reading a file. You open, write and close. Like before, I am going to use my
File_Temp
data-structure template to store my data in. I am also going to useab
as my open mode so API will create or overwrite the file if it already exists.Next is writing to that file, easy! Don't forget you must manually append line breaks (
x'25'
) if you want those in your stream file.So you can write as many times as you want, but do not forget to close the file!
And that's how you write to a file! Nice and simple, all within free-format RPG.