Code
(* 15.01.2014.
1. Разбор текстового файла сформированного при экспорте данных из Lotus Domino.
2. За основу взят класс BackgroundWorker и кое-что из класса IterativeBackgroundWorker, что в книге
Don Syme Expert F# 3.0.
3. Программа читает текстовый файл, анализирует его, переформировывает, записывает в новом виде на диск
в файл и в базу данных MSSQL.
4. with _ as err -> failwith err.Message - прерывает работу программы
*)
namespace LibraryFSharp.ParceTxtFileKmis
open System
open System.IO
open System.Text.RegularExpressions
open Microsoft.FSharp.Data.TypeProviders
open System.ComponentModel
open System.Windows.Forms
open System.Threading
//Определим исключение
exception ReadFileException of string
// Определим делегат для работы с C#
type Delegate = delegate of obj * System.EventArgs -> unit
// Определим тип для сформированных записей
type Record = {
mutable FIO_DR : string
mutable strComp : string
mutable numPolis : string
}
// Строка подключения к провайдеру SQL
type SqlConnection =
Microsoft.FSharp.Data.TypeProviders.SqlDataConnection<ConnectionString =
// @"Data Source=(LocalDB)\v11.0;Initial Catalog=KMIS;Integrated Security=True;
// Encrypt=False;TrustServerCertificate=False">
@"Data Source=(localdb)\Projects;Initial Catalog=KMIS;Integrated Security=True;Connect Timeout=30;Encrypt=False;
TrustServerCertificate=False">
// Создадим класс на основе BackgroundWorker
type ParseBackgroundWorker(inpFileName : string, outFileName: string) =
class
let worker = new BackgroundWorker(WorkerReportsProgress = true, WorkerSupportsCancellation = true)
// Создадим события на все случаи
let completed = new Event<Delegate, System.EventArgs>()
let error = new Event<Delegate, System.EventArgs>()
let cancelled = new Event<Delegate, System.EventArgs>()
let progress = new Event<Delegate, System.EventArgs>()
let started = new Event<_>()
// Выберем нужные поля
let predicat = @"field1:|field2:|field3:"
let repl str = Regex.Replace(str,predicat, "")
// Создадим пустую запись
let mutable client = {FIO_DR = ""; strComp = ""; numPolis= ""}
// Флаги начала и конца полей для одного человека
let mutable flagStart = false
let mutable flagStop = false
// Индекс для выходногоо массива
let mutable j = 0
// Функция выделения нужных полей
let readFile (fileName : string) =
try
fileName
|> File.ReadLines
|> Seq.filter(fun str -> Regex.IsMatch(str, predicat))
//|> Seq.map (fun s -> Regex.Replace(s,predicat, ""))
|> Seq.toArray
with | _ -> raise (ReadFileException("Ошибка чтения файла :" + inpFileName ))
// Событие запускается при вызове метода RunWorkerAsync()
do worker.DoWork.Add(fun args ->
// Прочитаем файл с диска
let data =
try
readFile inpFileName
with _ as err -> failwith err.Message
// Если все хорошо
let sizeArrayRecord = data.Length/10
let arrayRecord: (string array) = Array.zeroCreate sizeArrayRecord
// Цикл анализа масссива data
let select =
let rec parse i =
if i < (data.Length - 1) then
if worker.CancellationPending then args.Cancel <- true
else
let percent = int ((float (i + 1) / float (data.Length - 1)) * 100.0)
worker.ReportProgress(percent)
// Выделение полей
match data.[i] with
| var1 when var1.Contains(@"field1:") -> client.FIO_DR <- data.[i]; flagStart <- true
| var1 when var1.Contains(@"field2:") -> client.strComp <- data.[i]
| var1 when var1.Contains(@"field3:") -> client.numPolis <- data.[i]; if (flagStart = true) then flagStop <- true
| _ -> () //printfn "Нет ничего"
// Запись в массив arrayRecord
if flagStart && flagStop then
// Переведем запись в строку
let all = repl client.FIO_DR + " ;" + repl client.strComp + " ;" + repl client.numPolis
// Запишем в выходной массив
arrayRecord.[j] <- all
j <- j + 1
flagStart <- false
flagStop <- false
parse (i+1)
parse 0
arrayRecord
// Запишем сформированный массив в выходной файл
let nameFile = outFileName
try File.WriteAllLines(nameFile, select)
with _ as err -> failwith err.Message
// Получим контекст базы данных
let db = SqlConnection.GetDataContext()
// Функция записи в базу данных
let rec writeDataBase i =
if i < j then
let percent = int ((float (i + 1) / float (j- 1)) * 200.0)
worker.ReportProgress(percent)
let newRecord = new SqlConnection.ServiceTypes.Clients(Id = i, Fio = arrayRecord.[i], Strax="www", Polis ="334")
db.Clients.InsertOnSubmit(newRecord)
try
db.DataContext.SubmitChanges()
if worker.CancellationPending then args.Cancel <- true
else
writeDataBase (i + 1)
// Up trigger Error
with _ as e -> failwith e.Message
writeDataBase 0
// Конец процесса преобразования
args.Result <- box "O.K."
)
// Это событие возникает по завершению метода DoWork
do worker.RunWorkerCompleted.Add(fun args ->
if args.Cancelled then cancelled.Trigger(args.Error, System.EventArgs())
elif args.Error <> null then error.Trigger (args.Error, System.EventArgs())
else completed.Trigger (args.Result,System.EventArgs()))
// Отображение процесса
do worker.ProgressChanged.Add(fun args ->
progress.Trigger (args.ProgressPercentage,System.EventArgs()))
// Публикация методов
[<CLIEvent>]
member x.WorkerCompleted = completed.Publish
[<CLIEvent>]
member x.WorkerCancelled = cancelled.Publish
[<CLIEvent>]
member x.WorkerError = error.Publish
[<CLIEvent>]
member x.ProgressChanged = progress.Publish
member x.Started = started.Publish
member x.RunWorkerAsync() = worker.RunWorkerAsync()
member x.CancelAsync() = worker.CancelAsync()
end