Subscribe via RSS Feed Connect on LinkedIn

Dynamics NAV Export and Zip XMLPort Files

12th July 2015 0 Comments

A couple of years ago I was asked about Dynamics NAV file handling for zipping a file after exporting the data, at the time I looked at creating a batch file and scripting the zipping up of the exported file, however I prefer to do as much as possible from within Dynamics NAV, I have revisited this topic to see how I could do it in Dynamics NAV 2013 R2 using Dot Net assemblies, this example uses one of the Zip Files Classes that come with the Windows Dot.Net installed dll classes, the report used in this example can be downloaded at the end of this post.

A search on Google and I found the IO Compression ZipFile Create from Directory Class  on looking at the details I could not find a simple ‘’Zip a Single File” call, what this class does is to archive the contents of a directory to a zipped file, the points I had to consider were:

  • I might export one or more files to include in the zip archive.
  • The export directory folder must only contain the file or files I want to add to the zip.
  • The source and target directories must not be the same.
  • I might want to use the same file name and append a Date Time string for sequential files.

I decided to use a report for my example to enable beginners and intermediate level Dynamics NAV Developers to load the example report and be able to see and play with the code, the code and functions in the report could be transferred to a codeunit used in a production environment, the examples have only been tested on a local install of Dynamics NAV 2013 R2.

Export and Zip XMLPort Files

The steps in the example report to process a number of files into a zipped file were:

  • Create a report as processing only to test the file export.
  • Get a folder path if the user wants to copy the exported files to an archive folder.
  • Get the Zip folder path used to store the zipped exported files.
  • Get the Zip file name from the user.
  • Give the user an option to append a Date Time string to the files.
  • Test that the folder paths exist and the file name is valid.
  • Create a new unique folder using a GUID for the folder name.
  • Use one or more Dynamics NAV ‘Cronus’ XML Ports to export some test data.
  • Copy the exported files to the archive directory path.
  • Zip up all the files in the new temporary folder to the zip path and file name.
  • Delete the new temporary directory and files.

 
To start I created a blank report set as processing only and added the C/AL Global in the screenshot.
20150712165955
 
I added two text constants for message or error dialog.
20150712170012
 
To Get the Folder paths I added four variables to the report options form, the AppendDT check-box is to add a date time stamp to the files.
20150712165714
 

Request Page Control Code

It is important to test that the Folder paths exist, therefore I added code to the Options controls, I just used standard functions from the File Management codeunit 419.
 
OnValidate:

//Return the Folder Path from the Input
ArchiveFolder := FileMgmt.GetDirectoryName(ArchiveFolder);

 
On Lookup:

//Open a dialog window to browse for the folder
ArchiveFolder := FileMgmt.BrowseForFolderDialog('Archive File Folder','',TRUE);

 
To test that the file Name is valid, I added code to the Zip File Options controls, I just used standard functions from the File Management codeunit 419.
 
On Validate:

IF ZipName <> '' THEN BEGIN
  //Make sure no invalid characters are in the file name
  ZipName :=  FileMgmt.StripNotsupportChrInFileName(ZipName);

  //If the user as added a file extention then remove it
  i := STRPOS(ZipName,'.');
  IF i > 0 THEN
    ZipName := COPYSTR(ZipName,1,i-1);

  //Make sure the file name is valid, giving the user a chance to re-enter
  IF NOT FileMgmt.IsValidFileName(ZipName) THEN BEGIN
    MESSAGE(Text001);
    ZipName := '';
  END;
END;

 

On Pre-Report Trigger Code

For my example and to make sure no other files could exist in the target folder, I created a new unique folder using a GUID for the folder name and in this code I also use the Dot.Net Folder Helper variable copied from the codeunit 410 Global Variables.
 
There are two options when exporting data, firstly to replace the same file where the file name should be the same, secondly incremental file names by adding a unique sequential value to the file name, to do this I just used a Time Stamp value.
 
If in the process I have exported any files then the next process is to zip up all the files in the new folder to the zip path and filename entered on the options form.
 
The last step is to delete the new directory and files using a call to the Directory Helper delete with the recursive flag set to true as this will delete all the files as well as the temporary directory.
 

//Has the User entered a Zip Folder Name
IF ZipFolder = '' THEN
  ERROR(Text002,'Zip File Folder ');

//Has the User entered a Zip File Name
IF ZipName = '' THEN
  ERROR(Text002,'Zip File Name ');

//If the user requested a Date Time Stamp
IF AppendDT THEN
  TimeStamp := '-' + FORMAT(CURRENTDATETIME,0,'<Year><Month,2><Day,2><Hours24><Minutes,2><Seconds,2>')
ELSE
  TimeStamp := '';

//Set the Zip File Name
ZipFileName := DELCHR(ZipFolder,'>','\') + '\' + ZipName + TimeStamp +'.zip';

//Set the Temp GUID to use as a unique folder name
TempGUID := CREATEGUID;

//If the Achive Folder Path has been entered then use this folder to create the temporary directory
IF ArchiveFolder <> '' THEN
  XmlFolder := DELCHR(ArchiveFolder,'>','\') + '\' + FORMAT(TempGUID) + '\'
ELSE
  XmlFolder := DELCHR(ZipFolder,'>','\') + '\' + FORMAT(TempGUID) + '\';

//Use the Directory Helper to Create the Directory, User must have write permissions
IODirectory.CreateDirectory(XmlFolder);

//If the user is overwriting the zip file delete it
IF FILE.EXISTS(ZipFileName)THEN
  FILE.ERASE(ZipFileName);

//Clear the file counter variable
CLEAR(ExportCount);

//Call the function to export the Contacts XMLPort and update the counter
IF ExportXmlPort(XMLPORT::"Export Contact",'Contact','.txt')THEN
  ExportCount := ExportCount + 1;

//Call the function to export the Segment Contacts XMLPort, update the counter
IF ExportXmlPort(XMLPORT::"Export Segment Contact",'Segment-Contact','.txt')THEN
  ExportCount := ExportCount + 1;

//Clear the Dot.Net Zip Variable
CLEAR(IOCompress);

//Zip all the files in the Temporary Folder to the Zip File if the counter is set
IF ExportCount <> 0 THEN
  IOCompress.CreateFromDirectory(XmlFolder,ZipFileName);

//Delete the Temporary Directory recursive to delete files
IODirectory.Delete(XmlFolder,TRUE);

 
As part of the process I wanted the option to copy the exported files to the archive directory path so I have the original file, I coded to erase the file if it already existed.

Function ExportXmlPort Returns a Boolean value

ExportXmlPort(DataportNo: Integer; NewFileName: Text; Extention: Text) : Boolean;

Local Variables:

  • XmlFile: File;
  • XmlStream: OutStream;
  • IsExported: Boolean;

 

//Set the File name to Export
XmlFileName := DELCHR(XmlFolder,'>','\') + '\' + NewFileName + TimeStamp + Extention;

//If replacing the file delete the old file
IF FILE.EXISTS(XmlFileName)THEN
FILE.ERASE(XmlFileName);

//If archiving the files the set the Archive file name
IF ArchiveFolder <> '' THEN BEGIN
  ArchiveFileName := DELCHR(ArchiveFolder,'>','\') + '\' + NewFileName + TimeStamp + Extention;

  //If replacing the Archived Version then delete the old file
  IF FILE.EXISTS(ArchiveFileName)THEN
    FILE.ERASE(ArchiveFileName);
END ELSE
  ArchiveFileName := '';

//Clear the OutStream variable
CLEAR(XmlStream);

//Create the file and export the XMLPort into the Files OutStream
XmlFile.CREATE(XmlFileName);
XmlFile.CREATEOUTSTREAM(XmlStream);
IsExported := XMLPORT.EXPORT(DataportNo, XmlStream);
XmlFile.CLOSE;

//If the Export Ran ok then Archive the file if required
IF IsExported AND (ArchiveFileName <> '')THEN
  FILE.COPY(XmlFileName,ArchiveFileName);

//Return the IsExported Boolean
EXIT(IsExported);

 

Running the Report

I created a folder in my local Temp Folder, in production I would use a network folder that I knew the user had read and write permission for.
 
20150712170819
 
While the report is running a new folder has been created using a GUID as a unique folder name, to show this example screenshot I just remarked the code that deletes the folder.
 
20150712163116
 
After removing the remarks in the code and deleting the previous files, now when running the report I can now see a new zip file has been created.
20150712175144
 
Two sequential files have been written to the Archive folder, these could be used for audit or backup.
20150712175157
 
I hope the code in the download will be helpful, please feel free to comment on this post and discuss other Zip options.
 

Download “Report 50010 Dynamics NAV 2013 R2 Zip File Example” Dynamics-NAV-2013-R2-Report-50010-Zip-Files.zip – Downloaded 969 times – 15 KB


 

Leave a Reply

You must be logged in to post a comment.