Dot Net Fluke: Getting by on C# for iSeries RPG Developers

Useful tutorials on C# and .NET for RPG iSeries AS/400 developers. Brought to you from the folks at AranRock Consulting

7/30/08

Reading a C# Grid (Reading a subfile)

Previously I discussed how to write records to a C# grid -  the equivalent of an RPG subfile. But how do you read those records? Say you wanted to add totals entered to store in another table?

You might recall that unlike in RPG where we read a table and write each record from the table directly to a subfile, C# creates a layer between the physical data and the grid by using a data set. This is handy because you don't have to worry about updating multiple tables every time an update/add or delete is made to the grid, this is handled automatically when you define what tables belong to the data set.

Here is some code we used before to fill a data set:

// build a command object and prepare an SQL statement so that you can look at your table 


SqlCommand buildData = conn.CreateCommand(); 


cmd.CommandText = "Select * from Orders where OrdQty >100"; 


// Build the Data Adapater - this fills a data set 


SqlDataAdapter dataAdapter = new SqlDataAdapter(buildData); 


// Now create the data set. The data structure which contains the data retrieved by the data adapter 


DataSet orderDataSet = new DataSet(); 


// Populate the dataset with the Data Adapter 


dataAdapter.Fill(dataSet);



 



The data set defined above would be 'bound' to a grid as follows



DataGridView1.DataSource = ds.Tables.Item(0)



Now when the grid is displayed it will display orders from Orders file through the layer of the data set. Any changes made to the grid would be reflected in the data set.



To update the database simply use the adapater's update method



 this.custTableAdapter.Update(ds DataSet);




But back to our original question, how do you read the data in the data set for processing?


In RPG you could read each record in the subfile in a DOW loop, in C# you can use the For Each loop

which can read through data set as follows.


  foreach (DataRow rowx in ds.Tables(0))
{
totalInnings = totalInnings + rowx["Innings"];
}


The foreach statement is a powerful construct and makes processing data extremely simple. The above statement will process all the records in the subfile





and any processing just has to occur in between the curly brackets.









7/15/08

Read, write and delete files in windows

Sooner or later you'll need to access files from the Window's file system. You'll need to check if a file exists, delete it, move it  , you'll need to read and write to it and upload data from it to an iSeries table etc.

To illustrate how easy this is, I've included a full C# project.


This program cleans up a desktop. It moves unwanted items automatically to a 'clean up' folder automatically. Items you don't want to remove are maintained in a text file manually. This file is in 'CleanUp' on your desktop after you run it the first time.
Set it up to run in 'scheduled tasks' to run daily. My desktop gets absolutely splattered with downloads, images, files etc. etc.  Now it gets cleaned automatically and the stuff I want to keep is always there. Files are moved but not folders. 


The app demonstrates two things.

  1. How to access the windows file system
  2. How to write a RPG-like app in C#. i.e. in a procedural way  There is a 'main', an init etc. There are no class objects created, everything runs from the class. Methods are just like subroutines. Variables are defined that are needed throughout the application as public at the top of the class. (If you define a variable in a method - it is only available within that method.)

Please improve on this app and sent it back to share!

Download the attached visual studio project from here. (VS 2008)
If you just want the program executable itself download it here.

using System;
using System.Collections.Generic;

using System.Text;
using System.IO;

using System.Security.Principal;


//Lists each object on the desktop
//Checks if the object is in the list.
//If not, moves it to cleanup.

namespace ClearDesktop
{
class Program
{

// Declare class level variables that are accessible from all methods
public static string cleanUpFolder = @"Cleanup\";
public static string desktopPathAllUsers = @"
C:\Documents and Settings\All Users\Desktop\";
public static string desktopPath = "
";
public static string cleanUpPath = "
";
public static string cleanUpFile = "
";
public static string allowedOnDesktop = "
";



// Main Routine
static void Main(string[] args)
{
initializationRoutine(); // Set paths needed

RemoveFilesFromDesktop(desktopPath); // remove unwanted files
RemoveFilesFromDesktop(desktopPathAllUsers); // some file paths are in 'all users'
// Console.ReadLine();
}




public static void RemoveFilesFromDesktop(string dir)
{
// First create directory object from the desktop path
DirectoryInfo mainDir = new DirectoryInfo(dir);


// This single line fills an array called 'items' of everything on the desktop

// The items in the array are not strings but FileSystemInfo objects.


// What's cool here is each item has a ton of methods and properties


       // available directly from it.



            FileSystemInfo[] items = mainDir.GetFileSystemInfos();



// Now go through each item in the array and check if it is allowed
foreach (FileSystemInfo item in items)
{
// Check if the file on the desktop is in the 'allowed' file
bool allowedyn = allowedOnDesktop.Contains(item.Name.ToString());

if (item is FileInfo && !allowedyn)
{
// If it is to be moved any existing same name file has to be deleted
String alreadyExists = cleanUpPath + item;

if (File.Exists(alreadyExists))
{
try
{
// Delete the file with the same name
File.Delete(alreadyExists);
}
catch (Exception)
{


}

}

// Move the file on the desktop to the clean up folder
((FileInfo)item).MoveTo(cleanUpPath + item);

}

}
}




// Get a list of all the files allowed on the desktop
public static string WhatsAllowedOnTheDesktop(string logFileName)
{

string contents = "
";

using (FileStream fileStream = new FileStream(logFileName,
FileMode.Open,
FileAccess.Read,
FileShare.None))
{
using (StreamReader Reader = new StreamReader(fileStream))
{
contents = Reader.ReadToEnd(); // Reads the entire file in one statement
Reader.Close();
fileStream.Close();
}


}
return contents;
}

// Write to the 'Allowed files' directory those files you don't want to move
public static void WriteToLog(string logFileName, string data)
{
using (FileStream fileStream = new FileStream(logFileName,
FileMode.Append,
FileAccess.Write,
FileShare.None))
{
using (StreamWriter streamWriter = new StreamWriter(fileStream))
{
streamWriter.WriteLine(data);
}
}
}

// Do basic setup - path names etc.
public static void initializationRoutine() {
string username = getUserName();

desktopPath = @"
C:\Documents and Settings\" + username + @"\Desktop\";
cleanUpPath = desktopPath + cleanUpFolder;
cleanUpFile = cleanUpPath + @"
CleanUpFile.txt";

// If the cleanup directory does not exist, create it
if (!Directory.Exists(cleanUpPath))
{
Directory.CreateDirectory(cleanUpPath);
}

// Create the log file of items you want to keep on the desktop

if (!File.Exists(cleanUpFile))
{
File.Create(cleanUpFile);
}

allowedOnDesktop = WhatsAllowedOnTheDesktop(cleanUpFile);
}

// Get the log on name of the user who started the app in order
// to know the path of their desktop
public static string getUserName()
{
WindowsIdentity ident = WindowsIdentity.GetCurrent();

string userid = ident.Name;
string username = "
";
int pos = userid.IndexOf("
\\");
if (pos > -1)
{

username = userid.Substring(pos + 1);
}
else
{
username = userid;
}


return username;

}

}



}

Labels: , ,

7/7/08

When a method calls itself

This you can't do in RPG - have a method call itself. Sounds like something you would never use? Think again.

See this small console program that recurses through directories to get a list of folders and files. When the method finds a directory, it calls itself with the sub folder as a parameter whereupon the File part of the IF statement is executed.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;


namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Recurse(@"c:\temp");
}

public static void Recurse(string directory)
{
DirectoryInfo path = new DirectoryInfo(directory);
FileSystemInfo[] files = path.GetFileSystemInfos( );
foreach (FileSystemInfo file in files)
{
if (file is DirectoryInfo)
{
Console.WriteLine("Folder-> " + ((DirectoryInfo)file).FullName);


// Now the method calls itself passing in the subfolder name. When the method is called
all the files in the subfolder are listed

Recurse(((DirectoryInfo)file).FullName);
}
if (file is FileInfo)
{
Console.WriteLine("File-> " + ((FileInfo)file).FullName);
}

}



}

}
}


 



Labels: , , ,