In order to review files that have fixed-length fields, a human being usually has to count characters. One pair of tools often used for this purpose is a printer and a ruler. If you can align the printed font with numbered increments on a ruler, you have a quick physical tool to help you with this challenge. However, this is far from the paperless office we've been promised.
This tip offers a better way. It provides a page that displays the file 50 characters at a time, starting over again at each line break, which is marked in a distinctive manner to distinguish it from a long stretch of spaces within a line.
Each piece of the display has its own ruler, numbered appropriately. This lets an individual glance at the display to determine the position of a set of characters within any record.
<cfset Dirname=getDirectoryFromPath(getBaseTemplatePath())> <cfset EndChar=right(Dirname,1)> <cfset Dirname="#Dirname#dirin#EndChar#"> <cfdirectory action="list" directory="#Dirname#" name="Filelist">Create a select box in a form to pick a file from the directory. Set the first option to "~pick one~" as an obvious hint that a file must be selected. The cfdirectory tag returns a query; so, you can loop it as you would any other query. Loop the query, creating an option for each file that doesn't start with a period. (You don't want to offer to read a directory.) When the form is submitted, pass the name of the chosen file to review.cfm.
<form name="pickfile" action="review.cfm" method="post"> <select name="Filein"> <option>~pick one~ <cfloop query="Filelist"> <cfif left(filelist.name,1) is not "."> <option><cfoutput>#Filelist.name#</cfoutput> </cfif> </cfloop> </select> <input type="submit" name="doit" value="read"> </form>
<cfset Dirname=getDirectoryFromPath(getBaseTemplatePath())> <cfset EndChar=right(Dirname,1)> <cfset Dirname="#Dirname#dirin#EndChar#">
Knowing that your disk path ends in a backslash or forward slash, stick the filename to it and read the result. ColdFusion won't let the user read invalid filenames (such as "." or no name at all), but it will throw an error that says more than you might want it to say. To keep ColdFusion from giving the user the disk file path in an error message, use a try-catch combination (after you've tested your code) to supply your own error message and action as shown below.
<cftry> <cffile action="read" variable="Filetxt" file="#Dirname##form.Filein#"> <cfcatch> Invalid filename; press your back button to continue. <cfabort> </cfcatch> </cftry>
Then replace the character you'll use to show where the line ends - a tilde - with an underscore to avoid confusion. Finally, replace all carriage return/linefeed combinations with a single tilde (for Windows) and replace all bare linefeeds (for Unix) with a single tilde.
<cfset Filetxt=replaceNoCase(Filetxt,"~","_","all")> <cfset Filetxt=replaceNoCase(Filetxt,"#chr(13)##chr(10)#","~","all")> <cfset Filetxt=replaceNoCase(Filetxt,"#chr(10)#","~","all")>
After opening a cfoutput tag and a form, loop Filetxt; its record delimiter is now a tilde. Use the ceiling function to round up to a whole number of 50-character rows that will accommodate the record. If that number is less than one, the record is empty; set the LastRow to 1 and replace the record with a warning value.
You want the end of the displayed record to be immediately followed by a tilde. An easy way to do this is to append Endmark to every row but let it be empty for every row except the last one, when it finally gets to be a tilde. You also want to start with the first character; so, set Start to 1.
Begin looping rows from row 1 to the last row. If this is the last row, change the Endmark to a tilde so you'll know where the record ends.
<cfoutput>
<form>
<cfloop list="#Filetxt#" index="Record" delimiters="~">
<cfset LastRow=ceiling(len(Record)/50)>
<cfif LastRow lt 1>
<cfset LastRow=1>
<cfset Record="{Empty Record}">
</cfif>
<cfset EndMark="">
<cfset Start=1>
<cfloop from="1" to="#LastRow#" index="Row">
<cfif Row is LastRow>
<cfset Endmark="~">
</cfif>
You can surely find a fancy way to generate a different ruler for each row of a record. This code uses brute force: a separate ruler for each row. (It stops if more six rows are needed for a single record.) The following scheme provides a number whose FIRST character is on the count so that the "1" in "10" is on the tenth character, the "1" in "100" is on the one-hundredth character, etc. A "v" marks each half-way point: a place divisible by five but not by ten.
<cfif Row is 1> <cfset Ruler= "////v////10///v////20///v////30///v////40///v////50"> <cfelseif Row is 2> <cfset Ruler= "////v////60///v////70///v////80///v////90///v////100"> <cfelseif Row is 3> <cfset Ruler= "////v////110//v////120//v////130//v////140//v////150"> <cfelseif Row is 4> <cfset Ruler= "////v////160//v////170//v////180//v////190//v////200"> <cfelseif Row is 5> <cfset Ruler= "////v////210//v////220//v////230//v////240//v////250"> <cfelseif Row is 6> <cfset Ruler= "////v////260//v////270//v////280//v////290//v////300"> <cfelse> Max record length 300 characters; stopping... </cfif>
Use the pre tag to get a monospaced font with which to display the row. Each row consists of a chunk of the record (Record). The mid function begins with the current starting point (Start) and ends 50 characters later or with the end of the string, whichever is shorter. To determine the length from here to the end of the string, subtract the current starting point from the record length and add one. The min function helps out here to get the smaller number: 50 or this result. Append Endmark, a break in the page, and the ruler you've just defined. Close the pre tag. The placement of the pre tags will cause a break between rows. Add 50 to the starting point and loop to the next row. When the record is done, loop to the next record. When all records are done, close the form and the cfoutput tag.
<pre> #mid(Record,Start, min(50,len(Record)-Start+1))##EndMark#<br>#Ruler# </pre> <cfset Start=Start+50> </cfloop> </cfloop> </form> </cfoutput>
If you put data inside of textarea tags (one for each row) to make this page into an editor instead of just a viewer, you'll find that normal page text - including any ruler you supply - will lag the data in the field very slightly.
This lag is less noticeable when the ruler is placed below the data and contains forward slashes as the ones in this tip; because, the top of the slash, which would be aligned with the right edge of each data character, is nearly centered on each data character because of this lag. Thus, the same ruler design can be used for both display and edit.
So, build a ruler generator to support file review. Add the ability to edit and and save your changes. Then, share the wealth. =Marty=