Category Archives: F#

FreeBytes.exe (Disk Checker) Revisited

The library and application have been updated to be a little more flexible and take a parameter, so that the minimum free space does not have to be hard-coded into the program.

Here is VolLib, an F# library:

namespace Toa.volLib
open System
open System.Threading
open System.Collections.Generic
open System.Text
open System.IO
open Microsoft.Win32

type DiskFreeLevels =
           | DRIVE_OFF_LINE = -1L
           | GB1   = 1000000000L
           | GB5   = 5000000000L
           | GB10  = 10000000000L
           | GB20  = 20000000000L

[<AutoOpen>]
module volLib =
  let libInit = ref false

  let drive_list () =
    DriveInfo.GetDrives()

  // Takes a string representation of a drive, and pulls out its free space.
  let free_space drive =
      let di = DriveInfo(drive)
      if di.IsReady then
int64(di.AvailableFreeSpace)
      else
int64(-1)

      // Just convert bytes to gigabytes.
      let cvt_bytes_to_gb (in_bytes:int64) =
        int64(truncate((float(int64(in_bytes)) / float(1024L)
/ float(1024L)) / float(1024L)))

        let DRIVE_OFF_LINE = int64(-1)
        let GB1     = cvt_bytes_to_gb(int64(DiskFreeLevels.GB1))
        let GB5     = cvt_bytes_to_gb(int64(DiskFreeLevels.GB5))
        let GB10    = cvt_bytes_to_gb(int64(DiskFreeLevels.GB10))
        let GB20    = cvt_bytes_to_gb(int64(DiskFreeLevels.GB20))
// This is a pipeline function that takes a drive letter (string) and
// returns the free GB from a DriveInfo structure.
         let cvt_drive_to_free_gb drive =
             let fs = free_space drive
             if fs > DRIVE_OFF_LINE then
                free_space drive |> cvt_bytes_to_gb
             else
                int64(-1)

             let cvt_gb_arg_to_int (arg:string) =
                 let numeric_arg = arg.Substring(2, arg.Length - 4)
                 int64(numeric_arg)

and the main application


(*
A simple checker of Windows disks.
Charles M. Norton   11/01/2016
Will be greatly improved over time.

Modifications
Charles M. Norton   11/1/2016
Initial version.
*)

open System
open System.Text
open System.Net.Mail
open System.IO
open System.Threading
open Microsoft.VisualBasic.FileIO
open System.Collections.Generic

open Toa.volLib // local library

let send_email msg =
 use msg =
 new MailMessage ("dbadmin@somewhere.sometown.us",
@"dbadmin@town.arlington.ma.us", @"Disk Space Report\n",
   msg )
use client = new SmtpClient(@"webmail.somewhere.sometown.us")
client.DeliveryMethod <- SmtpDeliveryMethod.Network
  client.Credentials <-
new System.Net.NetworkCredential("dbadmin", "xxxxxx")
  client.Send msg

let match_head = "--"
let match_tail  = "GB"

let contains_match_constants (arg:string) =
    if arg.StartsWith match_head && arg.EndsWith match_tail then
       true
    else
       false

let parse_min_gb_arg arg =
    if contains_match_constants arg then
       cvt_gb_arg_to_int arg
    else
       volLib.GB1

let no_disk = int64(-1)

[<EntryPoint>]
let main argv =
    let min_gb =
    if argv.Length > 0 then
       parse_min_gb_arg argv.[0]
    else
       volLib.GB1

    let local_drive_list = drive_list ()

    let check_file = "free_bytes_check.txt"
    let system_name = System.Environment.MachineName
    let system_drive = Path.GetPathRoot(Environment.SystemDirectory)

    let display_info = new List<string>()
    display_info.Add("System name " + system_name + "\n")

    let drive_list_len = local_drive_list.Length

    for idx = 0 to (drive_list_len - 1) do
        let drive_name = (Seq.item idx local_drive_list).Name
        let free_gb = cvt_drive_to_free_gb drive_name
        let display_row = "Volume: " + drive_name + "\n" + "Free Space: " +
free_gb.ToString() + "GB\n"
        display_info.Add(display_row)

    let curr_time = DateTime.Now

    let gb_c = cvt_drive_to_free_gb system_drive
    let gb_d = cvt_drive_to_free_gb "D:\\"

    let gbs = display_info |> String.concat("\n")

    if not (File.Exists check_file) then
       use swH = new StreamWriter(check_file, true)
       swH.WriteLine(curr_time.ToString())
       send_email gbs
    else
       let fAccessDate = File.GetLastAccessTime(check_file)
       let update_stamp = curr_time.Subtract(fAccessDate).Duration() <
TimeSpan.FromDays(7.0)

    if not(update_stamp) then
       File.WriteAllText(check_file.ToString(), String.Empty)
       use swH = new StreamWriter(check_file, true)
           swH.WriteLine(curr_time.ToString())
       send_email gbs

    if gb_c < min_gb || ((gb_d > no_disk) && gb_d < volLib.GB20) then
       printfn "Disk free space is below thresholds; send out warning email."
       send_email gbs
    else
       printfn "Disk free space is at or above thresholds. "
printfn "All is well, at least for now."</pre>
<pre>    printfn "Sleeping 5 seconds to let you read."
    Thread.Sleep 5000 |> ignore
0 // return an integer exit code

Leave a comment

Filed under F#

F# Free Disk Space

So, here is a small, F# program to report on disk usage. This is from a real example on our Munis server.


(*
A simple checker of Windows disks.
Charles M. Norton   11/01/2016
Will be greatly improved over time.

Modifications
Charles M. Norton   11/1/2016
Initial version.
*)

open System
open System.Text
open System.Net.Mail
open System.IO
open System.Threading

open Toa.volLib // local library

let SendEmail msg =
use msg =
new MailMessage (
"dbadmin@town.arlington.ma.us", @"itadmin@town.arlington.ma.us", @"Munis Server Disk Space Report\n",
msg )

use client = new SmtpClient(@"webmail.town.arlington.ma.us")
client.DeliveryMethod client.Credentials client.Send msg

let main argv =
let localDriveList = driveList ()
let dn = (Seq.head(localDriveList)).Name

let drive_c = (Seq.head(localDriveList)).Name
let data_drive = (Seq.nth(1) localDriveList).Name

let fs_c = freeSpace drive_c
let fs_d = freeSpace data_drive

let gb_c = cvtBytesToGB fs_c
let gb_d = cvtBytesToGB fs_d

let system_name = System.Environment.MachineName

let strings = ["System name: "; system_name; "Volume "; drive_c; gb_c.ToString(); "GB\n"; "Volume"; data_drive; gb_d.ToString(); "GB\n"]
let gbs = String.concat " " strings
printfn "System name: %A: Drive C %f -- Data Drive %f" system_name gb_c gb_d

if gb_c < volLib.GB5 || gb_d < volLib.GB5 then printfn "Disk free space is below thresholds; send out warning email." SendEmail gbs else printfn "Disk free space is at or above thresholds. All is well, at least for now." printfn "Sleeping 5 seconds to let you read." Thread.Sleep 5000 |> ignore
0 // return an integer exit code

Leave a comment

Filed under F#

A Utilitarian F# Library

I started building an F# library that could be used to hold housekeeping routines. This is the start of that library.

namespace Toa.volLib
open System
open System.Threading
open System.Collections.Generic
open System.Text
open System.IO
open Microsoft.Win32

type DiskFreeLevels =
  | GB1   = 1000000000L
  | GB5   = 5000000000L
  | GB10  = 10000000000L

[<AutoOpen>]
module volLib =
  let libInit = ref false

  let driveList () =
    DriveInfo.GetDrives()

  let freeSpace drive =
    let di = DriveInfo(drive)

  if di.IsReady then int64(di.AvailableFreeSpace)
  else int64(DiskFreeLevels.GB10)

  let cvtBytesToGB (inBytes:int64) =
    truncate((float(int64(inBytes)) / float(1024L) / float(1024L)) / float(1024L))

  let GB1     = cvtBytesToGB(int64(DiskFreeLevels.GB1))
  let GB5     = cvtBytesToGB(int64(DiskFreeLevels.GB5))
  let GB10    = cvtBytesToGB(int64(DiskFreeLevels.GB10))

Leave a comment

Filed under F#

F#: Reading From Console

open System

let readInput() =
   Seq.initInfinite (fun _ -> Console.ReadLine())
   |> Seq.takeWhile (fun s -> not (s.Equals("")))
   |> Seq.map int

There are a lot of ways to read information from the console, and with GUIs
having been around a long time, console I/O is not as big a deal as it
was years ago. For F#, this seems to be a good way to read integers from the command line, and then convert them from ASCII to int.

From a sequence, conversion is possible to an array or list.

Leave a comment

Filed under F#

So an F# Sequence Should Stick Around For a While

If you create a sequence in Clojure, the sequence sticks around within the scope of its creation. That is, once a Clojure sequence is created and bound to a var, nothing special has to be done to make sure its contents stick around. This is not so with F#.

Take this program


open System
open System.Collections.Generic
open System.Text
open System.IO
#nowarn "40"

let rec readLines () =
    seq {
    let line = Console.ReadLine()
    if not (line.Equals("")) then
           yield Int32.Parse(line)
           yield! readLines ()
    }

[<EntryPoint>]
let main argv =
    let inSeq = readLines ()    

    inSeq

    |> Seq.length

    |> printfn "%d lines read"

    // This will keep it alive enough to read your output
    Console.ReadKey() |> ignore
    0

Because of a sequences’ inherent laziness, the reading in of numbers does not begin until inSeq’s length is computed. Without caching inSeq, you will have to read the integers in again if you want to iterate the sequence, unless this change is made


let inSeq = readLines () |> Seq.cache

Leave a comment

Filed under Clojure, F#

Generating F# Sequences From Console Input

I got a very nice answer on SO to why a function was not executing.


open System
open System.Collections.Generic
open System.Text
open System.IO
#nowarn "40"

let rec readlines () =
     seq {
           let line = Console.ReadLine()
           if not (line.Equals("")) then
              yield line
              yield! readlines ()
}

[<EntryPoint>]
let main argv =
      let inSeq = readlines ()

      inSeq
      |> Seq.length
      |> printfn "%d lines read"

      // This will keep it alive enough to read your output
      Console.ReadKey() |> ignore
      0

Leave a comment

Filed under F#

Nice F# List.fold example

Got this example from here.


open System
open System.Threading
open System.Collections.Generic
open System.Linq
open System.Text
open System.Threading.Tasks
open System.IO
open Microsoft.VisualBasic.FileIO


let main argv =
   let data = [(Cats,4);
               (Dogs,5);
               (Mice,3);
               (Elephants,2)]

   let count = List.fold (fun acc (nm,x) acc+x) 0 data
   printfn "Total number of animals: %d" count


Even though I’ve used map and other functions in Clojure, I’ve forgotten the basics of an inline function. The value of 0 is assigned to nm, and x takes on the first row of data.

 

Leave a comment

Filed under F#

Reading in a .csv file

Yes, it is my favorite subject, which is transforming data in .csv files. Here’s reading data into a variable in F#.


open System
open System.Threading
open System.Collections.Generic
open System.Linq
open System.Text
open System.Threading.Tasks
open System.IO
open Microsoft.VisualBasic.FileIO

[<EntryPoint>]
let main argv =
  let csv_fileH = new TextFieldParser(test1.csv)
  csv_fileH.TextFieldType = FieldType.Delimited |> ignore
  let x = csv_fileH.SetDelimiters(',')
  let csv_data = new List string[]()

  let eod = csv_fileH.EndOfData

  if not eod then
    let column_headings = csv_fileH.ReadFields()
    csv_data.Add(column_headings) |> ignore

    // Parentheses are needed after function definition to produce type bool.
    let read_rest_of_csv() =
    csv_data.Add(csv_fileH.ReadFields()) |>
    not csv_fileH.EndOfData

    while read_rest_of_csv() do ignore None

  0 // return an integer exit code

This program is associated on stackoverflow with some very good answers to a question I asked.

Leave a comment

Filed under F#

A First [and Simple] F# Sample

Anything worth learning should not be simple. Learning Clojure was not simple, and hacking with C# for the first time was not simple either, so I should not expect simple while learning F#.

Here is a first small program, because I have found a dirth of regular simple examples out on the web, especially those calling .Net functions.


 open System
 open System.Threading
 open System.Collections.Generic
 open System.Linq
 open System.Text
 open System.Threading.Tasks
 open System.IO
 open Microsoft.VisualBasic.FileIO

[EntryPoint]
let main argv =
    let parser = new TextFieldParser(&quot;test1.csv&quot;)
    parser.TextFieldType = FieldType.Delimited |&amp;amp;amp;gt; ignore
    let x = parser.SetDelimiters(&quot;,&quot;)

    let eod = parser.EndOfData
    if not eod then
        let column_headings = parser.ReadFields()
        printf &quot;%A&quot; column_headings |&amp;amp;amp;gt; ignore
0 // return an integer exit code

This is the contents of test1.csv

&lt;br data-mce-bogus=&quot;1&quot;&gt;

AGY/DIV,STS,GIC-ID,LAST-NAME,FIRST-NAME,COVERAGE DESCRIPTION,PREMIUM,RUN-DATE,BILL MONTH&lt;br data-mce-bogus=&quot;1&quot;&gt;

 

Leave a comment

Filed under F#