Besides data import/export, CSV files could be used for integration between systems. It is probably the most simple integration approach. I've seen and worked on a number of projects where an external application, for example a specialized billing system, generates CSV files every day. Dynamics AX runs a periodic batch job, which reads the generated files every night and imports the data, for instance, sales orders. Although this is not a real-time integration, in most cases it does the job and does not require any additional components like Dynamics AX Application Integration Framework or something similar.
Another well known example is when external companies are hired to manage the payroll. On a periodic basis, they send CSV files to the finance department, which are then loaded into the General journal in Dynamics AX and processed as usual.
In this recipe, we will learn how to read CSV files from code. As an example, we will process the file created in a pervious recipe.
In AOT, create a new class named ReadCommaFile with the following code. Replace
<documents>
with your own path (use double backslashes for folder separation, i.e.\\
):class ReadCommaFile { } public static client void main(Args _args) { CommaIo file; container line; #define.filename('<documents>\\accounts.csv') #File ; file = new CommaIo(#filename, #io_read); if (!file || file.status() != IO_Status::Ok) { throw error("File cannot be opened."); } while (file.status() == IO_Status::Ok) { line = file.read(); if (line != connull()) { info(con2str(line, ' - ')); } } }
Run the class to view the file's content:
.
As in the previous recipe, we first create a new file
object using CommaIo. This time we use #io_read
as the mode to make sure that the existing file is opened for reading only. We also perform the same validations to make sure that the file object is correctly created, otherwise we show an error message.
Next and finally, we read the file line by line until we reach the end of the file. Here we use the while
loop until the file status changes from IO_Status::OK
to IO_Status::FileTooShort
, which means no more lines exist in the file. Inside the loop, we call read()
on the file
object, which returns the current line as a container and moves the internal file cursor to the next line. File data is then simply outputted to the screen using the standard global info()
function in conjunction with con2str()
, which converts a container to a string for displaying.
The last element of code where data is outputted normally should be replaced by proper code that processes the incoming data.
File reading, like file writing, could also be executed on a server to improve performance. The modifier client
has to be changed to server
, and code with the FileIoPermission class has to be added to fulfill the code access security requirements. The modified class should look like the following:
class ReadCommaFileServer { } public static server void main(Args _args) { CommaIo file; container line; FileIoPermission perm; #define.filename('<documents>\\accounts.csv') #File ; perm = new FileIoPermission(#filename, #io_read); perm.assert(); file = new CommaIo(#Filename, #io_read); if (!file || file.status() != IO_Status::Ok) { throw error("File cannot be opened."); } while (file.status() == IO_Status::Ok) { line = file.read(); if (line != connull()) { info(con2str(line, ' - ')); } } CodeAccessPermission::revertAssert(); }