Найти тему
Некто

Статья 9. Перенос данных из dbf файлов в текстовый файл на VBScript с использованием ADO. Создание разделителей.

В 8 статье я показал, как перенести данные из текстового файла в создаваемый dbf файл. Я отметил, если текстовый файл очень большой, то очень затруднительно это сделать. Текстовый файл с разделителями может не помещаться на лист формата A4 и даже на формат A3. Тогда надо думать какие данные надо перенести и как еще это сделать. Если в редакторах FAR, и др. аналогичных можно еще увидеть упорядоченную разбивку данных как бы по полям, то в Блокноте и WordPad не всегда можно получить приличный вид текстового файла. Количество полей в dbf файлах на сегодня 254 по 254 символа (текст), а в некоторых приложения может быть и больше. При переносе из текстового файла надо это учитывать. Во фрагменте

'==============Ввод названий Полей базы данных для DBF

SQL="create table " & fileDBF & "("

for i=1 to 4 ' Если взять 15

stPol="st"&i

stDL= 19 ' Если взять 254

if i=4 then ' Если взять 15

SQL=SQL & "st" & i & " char(" & stDL & "))"

else

SQL=SQL & "st" & i & " char(" & stDL & "),"

end if

next

'==============Ввод названий Полей базы данных для DBF

Тут тоже можно сделать автоматический поиск и определить количество символов разделителей, если Вы уверены, что это тот разделить, или что Вам необходимо.

'========== Количество столбцов =======

Kstl=0

Str = Trim(TextStream.ReadLine())

for i=1 to Len(str)

if Mid(str,i,1)="|" Then

Kstl=Kstl+1

end if

next

if Kstl=0 then

WScript.Echo("Неправильно указан символ разделитель или нет такого символа")

WScript.Quit

end if

и отсюда

'==============Ввод названий Полей базы данных для DBF

SQL="create table " & fileDBF & "("

for i=1 to Kstl

stPol="st"&i

stDL= 19 ' Здесь можно подобрать длину поля (имя)

if i=Kstl then

SQL=SQL & "st" & i & " char(" & stDL & "))"

else

SQL=SQL & "st" & i & " char(" & stDL & "),"

end if

next

Но вот длину надо все-таки надо уточнять. Это не EXCEL и dbf формат. Да, можно проскочить файл и выбрать то же автоматически, но при этом все столбцы должны находиться на одном символьном расстоянии. Тогда это будет выглядеть так

'========== Количество символов в столбце =======

ReDim MassStrS(Kstl),MassRaz(Kstl)

k=0

Str = Trim(TextStream.ReadLine())

for i=1 to Len(str)

if Mid(str,i,1)="|" Then

k=k+1

MassStrS(k)=i

end if

next

for i=1 to Kstl

MassRaz(i)=(MassStrS(i)-MassStrS(i-1))-1

next

'========== Количество символов в столбце =======

Если же искать максимальную длину поля, то надо просмотреть весь текстовый файл.

Если же он небольшой, то можно сделать это быстро, а так надо довериться алгоритму.

'========== Максимальное количество символов в столбце =======

ReDim MassStrS(Kstl),MassMax(Kstl),MassRaz(Kstl)

nn=0

Do While Not TextStream.AtEndOfStream

k=0

nn=nn+1

Str = Trim(TextStream.ReadLine())

for i=1 to Len(str)

if Mid(str,i,1)="|" Then

k=k+1

MassStrS(k)=i

end if

next

for i=1 to k 'или Kstl

if nn=1 then

MassMax(i)=MassStrS(i)

else

if MassMax(i)<MassStrS(i) then

MassMax(i)=MassStrS(i)

end if

end if

Next

loop

SumSimv=0

for i=1 to Kstl

MassRaz(i)=(MassMax(i)-MassMax(i-1))-1

SumSimv=SumSimv+MassRaz(i)

Next

И это для того чтобы узнать значение SumSimv и оно должно быть меньше 3810, потому что переменная SQL может перенести только 3810 символов (254 символов на 15 полей-заголовок).

if SumSimv>3810 then

WScript.Echo("Общее количество символов больше 3810")

WScript.Quit

end if

'========== Максимальное количество символов в столбце =======

И опять меняем

'==============Ввод названий Полей базы данных для DBF

SQL="create table " & fileDBF & "("

for i=1 to Kstl

stPol="st"&i

stDL= MassRaz(i) ' Здесь есть длина поля (имя)

if i=Kstl then

SQL=SQL & "st" & i & " char(" & stDL & "))"

else

SQL=SQL & "st" & i & " char(" & stDL & "),"

end if

next

'==============Ввод названий Полей базы данных для DBF

И опять и снова

Set TextStream = FileName.OpenAsTextStream(1)

А можно и вот так

ReDim MassStrS(Kstl),MassMax(Kstl)

iss=1

nn=0

While Not TextStream.AtEndOfStream

Str = TextStream.ReadLine()

nn=nn+1

for j=1 to Kstl

InSimv=InStr(iss,Str,"|",1) ' Ставим символ разделитель строки

st=Trim(Mid(Str,iss,InSimv-iss))

MassStrS(j)=len(st)

if MassStrS(j)=0 then

MassStrS(j)=9 ' Если поле пустое т.е. имеет текст состоящий из одних пробелов

end if

if nn=1 then

MassMax(j)=MassStrS(j)

else

if MassMax(j)<MassStrS(j) then

MassMax(j)=MassStrS(j)

end if

end if

iss=InSimv+1

next

iss=1

Wend

nn=0

Erase MassStrS

SumSimv=0

for i=1 to Kstl

SumSimv=SumSimv+MassMax(i)

next

Это уже с нормализацией, но можно сделать из dbf файла. В общем можно придумать множество решений и алгоритмов определения необходимой длины столбца (количество символов строки в колонке, если правильно указан символ разделитель). Можно создать массив полей и автоматически записать в dbf файл. В текстовый файл можно скидывать по строке до 2 гб. символов. Сам я не проверял, но в редакторе FAR просматривал большие файлы и строки в них были больше указанного количества символов 3810. В ИНТЕРНЕТе Я видел это решение. В основном решается как рекурсия. Из этого значит, что большие по своему объему dbf файлы могут перевести все данные в текстовый файл, и они уместятся, но опять же не превышая 2 гб. А вот перевести из текстового файла в dbf автоматически иногда проблематично из определенных ограничений. Да можно перенести выделенные данные, но их надо еще подготовить к этому. Если файл небольшой то его можно как то к этому приспособить, а если большой, то уж как получиться. Конечно, можно попросить Айти специалиста или Программиста за это взяться. И этим довести их до паники и бегства. А потом, если у этих специалистов нет на это решения, то они могут вообще отстраниться от этого. И начальство заставит Вас думать, как это сделать, а им будет СЛАВА. Тогда встал вопрос, а зачем переносить данные из dbf в текстовый файл. Сумасшествие рядом и как отпустить такую ситуацию, перескочившей горизонт событий от нечего делать. Давайте подумаем так. Вам необходимо посмотреть, что находится в dbf файле, и специальных штатных приложений нет. Просматривать dbf с помощью Блокнота и в других, не приспособленных для этого редакторах тяжко, и если Вы вообще не разбираетесь в структуре dbf, то запутаетесь, и может пропасть желание в дальнейшем узнавании. Все редакторы, которые входят в состав OC, не приспособлены, оказать Вам помощь в этом. Также можете отредактировать некоторые данные и даже если их немного вернуть опять в dbf с определенными параметрами (тип, длина и т.д.). Вот здесь можно немного поработать и также освоиться, если Вам это необходимо. Причем Вы можете понять, какие поля необходимы, а какие нет. В текстовый файл можно сохранить с помощью WDBFVIEW и др., но если они у Вас есть. Здесь вы не подведете шапку с заголовками, и если в строке будут переводы строк, то в некоторых случаях Вы получите кашу символов, которую Вам придется так сказать разгребать, а проще исправлять и приводить к читабельному порядку. Конечно, ко всему возможно приспособиться, но это время и хорошо, если Вы властелин времени или Ваши сотрудники это знают. Здесь есть непреодолимое желание смотреть на все проще, но не всегда так выходит. Из всего этого есть понятие, что все взаимозаменяемо и ничего нового. Если можно создать dbf или EXCEL файл и др. то перевести их в текстовый файл или обратно или друг в друга, не сложно, если знать инструменты перевода. А это и приложения и программы и немного понятия, что это такое и для чего Вам это нужно или необходимо. Теперь рассмотрим и разберем скрипт, с помощью которого выводим данные из dbf файла в текстовый файл. В основном под текстовым файлом будем просто подразумевать файл TXT.

'*******************************************************************

' Имя: AdoED9Z.vbs

' Язык: VBScript

' Описание: Вывод данных из DBF файла в TXT

' Автоматическое создание шапки (в заголовках свои имена полей)

' Замена в строке символа ПЕРЕВОДА СТРОКИ на пробел

' ODBC и ADO только для dBase

'*******************************************************************

Set WshShell=WScript.CreateObject("WScript.Shell")

SDefaultDir=WshShell.CurrentDirectory

Set FSO = CreateObject("Scripting.FileSystemObject")

FileTekst=SDefaultDir & "\_TEKST.txt" 'Текстовый файл вывода

'=========== Проверка файла

Set FSO = CreateObject("Scripting.FileSystemObject")

If FSO.FileExists(FileTekst) Then

'MsgBox "Файл есть! Удаляем"

FSO.DeleteFile FileTekst

End if

'========== Проверка файла

NameFilDBF=SDefaultDir & "\_222.dbf"

'========== Проверка файла

If FSO.FileExists(NameFilDBF) Then

else

MsgBox "Нет файла "&NameFilDBF

WScript.Quit

end if

'========== Проверка файла

'======== Если данные в файле с не русской кодировкой устанавливаем 866 Если с русской можете заремачить =======

Set oFile = FSO.GetFile(NameFilDBF)

With oFile.OpenAsTextStream()

readBinary = .Read(oFile.Size)

.Close

End With

readBinary=left(readBinary,29)+"e"+mid(readBinary,31)

With FSO.createTextFile(NameFilDBF)

.Write(readBinary)

.Close

End With

'======== Если данные в файле с не русской кодировкой устанавливаем 866 =======

FileTekst=SDefaultDir & "\_TEKST.txt" 'Файл вывода

'=========== Проверка файла

Set FSO = CreateObject("Scripting.FileSystemObject")

If FSO.FileExists(FileTekst) Then

'MsgBox "Файл есть! Удаляем"

FSO.DeleteFile FileTekst

End if

'========== Проверка файла

'=================== dBase ==================

Set RSN=WScript.CreateObject("ADODB.Recordset")

Set conn = CreateObject("ADODB.Connection")

conn.CursorLocation = 3

conn.Open "Driver={Microsoft dBase Driver (*.dbf)};DBQ=" & SDefaultDir & ";"

strSQLdbf="SELECT * FROM " & NameFilDBF & " "

Set RS = conn.Execute(strSQLdbf)

objKlRecs=RS.RecordCount 'Количество строк в DBF файле

objKlFields = RS.Fields.count 'Количество колонок в DBF файле

'=================== dBase ==================

'=================== Максимальное значение поля в DBF ==========

ReDim MassDL(objKlFields-1)

for i=0 to objKlFields-1

st=RS.Fields(i).Name

strSQLnn="SELECT Max(Len(" & st & ")) FROM " & NameFilDBF & " "

set RSQQ = conn.Execute(strSQLnn)

v=RSQQ.Fields (0).Value

if IsEmpty(v) then

v=9

end if

if IsNull(v) then

v=9

end if

if v="" then

v=254

end if

if v=0 then

v=9

end if

MassDL(i)=v

v=""

next

v=0

RSQQ.Close

Set RSQQ = Nothing

'=================== Максимальное значение поля в DBF ==========

Const ForWriting = 2 ' На запись

Set FOut = FSO.OpenTextFile(FileTekst,ForWriting,true)

' ==============Ввод названий Полей базы данных

FOut.WriteLine NameFilDBF 'Вывод имен полей DBF

FOut.WriteLine "==================================================================================="

FOut.WriteLine "№ |Наименование поля|Тип поля | Длина поля (байт)"

FOut.WriteLine "==================================================================================="

StrP="" 'Можете это и не ставить

TypeP=""

RazmP=""

UmolP=""

ZnacP=""

McifP=""

Nnom=0

for i=0 to objKlFields-1

Nnom=Nnom+1

StrP=RS.Fields(i).Name

TypeP=RS.Fields(i).Type

RazmP=RS.Fields(i).ActualSize

UmolP=RS.Fields(i).DefinedSize

ZnacP=RS.Fields(i).NumericScale

McifP=RS.Fields(i).Precision

Nnom=Space(3-Len(Nnom))&Nnom

if len(StrP)<>17 then

StrP=StrP+Space(17-Len(StrP))

else

StrP=Left(StrP,17)

end if

if TypeP=200 then

Tpolzn="Строковое значение"

else

if TypeP=5 then

Tpolzn="Целое с плавающей запятой двойной точности"

else

if TypeP=133 then

Tpolzn="Дата"

else

Tpolzn="Тип неопределен" 'Возможен другой тип

end if

end if

end if

if len(Tpolzn)<>42 then

Tpolzn=Tpolzn+Space(42-Len(Tpolzn))

else

Tpolzn=Left(Tpolzn,42)

end if

if len(UmolP)<>18 then

UmolP=Space(18-len(UmolP))&UmolP

else

UmolP=Left(UmolP,18)

end if

FOut.WriteLine Nnom & " " & StrP & " " & Tpolzn & " " & UmolP

next

FOut.WriteLine "==================================================================================="

FOut.WriteLine

strStb=""

StrP=""

ReDim DlStrS(objKlFields-1)

for i=0 to objKlFields-1

stDL=MassDL(i)

StrP=RS.Fields(i).Name

if stDl<Len(StrP) then

stDL=Len(StrP)

end if

if i=objKlFields-1 then

'strStb=strStb & StrP & Space(stDL-Len(StrP)) ' Оставил если не нужна завершающая литера в конце заголовка

strStb=strStb & StrP & Space(stDL-Len(StrP)) & "|"

else

strStb=strStb & StrP & Space(stDL-Len(StrP)) & "|" ' Можете поставить свой символ разделить по колонкам

end if

DlStrS(i)=len(StrP+Space(stDL-Len(StrP)))

next

FOut.WriteLine String(len(strStb),"=")

FOut.WriteLine strStb

FOut.WriteLine String(len(strStb),"=")

' ============== Ввод данных из DBF файла

for i=1 to objKlRecs

vvv=""

for j=0 to objKlFields-1

stShap=DlStrS(j)

st=Trim(RS.Fields(j))

if IsNull(st) then

st=" "

else

st=UprSimv(st) 'Функция замена символа ПЕРЕВОДА СТРОКИ в строке символов

end if

if j=objKlFields-1 then

'vvv=vvv & st & "" 'Оставил, если не понадобится последняя колонка

vvv=vvv & st & "" & space(stShap-len(st)) & "|"

else

vvv=vvv & st & "" & space(stShap-len(st)) & "|"

end if

next

FOut.WriteLine vvv

' FOut.WriteBlankLines 2 ' записать в файл указанное количество пустых строк

RS.MoveNext

next

'-----------------------

Function UprSimv(s) 'Поиск символа перевода строки и замена его на пробел

ss=""

' Здесь можно явно указать переменную с помощью DIM i и убрать ii

For ii=1 To Len(s) ' Проверяем все символы в строке.

k = Asc(Mid(s,ii,1)) ' Рассматриваем и определяем ANSI-код каждого символа. Шаг 1 символ в строке

ks=Mid(s,ii,1)

'Кроме перевода строки может попасться и что то другое

if k=10 then 'Находим символ перевода строки

ss= left(ss,LEN(ss)-1)

ks=chr(32)

ss=ss+ks

else

ss=ss+ks

end if

Next

UprSimv=ss

End Function

'-----------------------

Erase MassDL

Erase DlStrS

FOut.WriteLine String(len(strStb),"=")

Set WshShell=Nothing

Set FSO = Nothing

Set oFile=Nothing

FOut.Close

Set FOut=Nothing

conn.close

Set conn = Nothing

Set RS = Nothing

Set RSN = Nothing

WScript.Echo("Файл создан!")

WScript.Quit

Да, текст получился большой, но можно и переделать.

А вот так выглядит итоговое решение

Эти данные перенесены из файла _222.dbf. Смотрятся данные этого файла так:

-2

Вытащить текстовую информацию из рисунка можно современными действиями Гугл и Яндекс если файл небольшой и количество полей и данных не так много, но а так только переводом информации. Есть еще вариант как сделать еще легче, но здесь я не показал шапку с заголовками.

v=RS.GetString 'Вывод в текст'

Set objFSO = CreateObject("Scripting.FileSystemObject")

Set tsOut = objFSO.CreateTextFile("FileTxt.txt", True, False) 'создаём файл в ASCII, при наличии файл перезаписывается

tsOut.WriteLine v

Set WshShell=Nothing

Set FSO = Nothing

Set RS = Nothing

Set objFSO=Nothing

tsOut.Close

Set tsOut=Nothing

conn.close

Set conn=Nothing

WScript.Echo("Файл создан!")

Выбирать каждому свое.

В скрипт AdoED9Z.vbs можно добавить вот такой фрагмент и создаем файл AdoED9U.vbs

Set objArgs=WScript.Arguments

if objArgs.Count>0 then

fileVvod=objArgs(0)

else

WScript.Echo "Введите имя файла DBF после AdoED9U.vbs"

WScript.Quit

end if

' ==== Ввод файла dbf через строку данные которого надо перевести в создаваемый во время процесса текстовый файл ====

NameFilDBF = FSO.GetFile(fileVvod)

'========== Проверка файла

sStr=len(trim(NameFilDBF))

if uCase(Mid(trim(NameFilDBF),sStr-3,4))<>".DBF" then

MsgBox "Это не файл DBF"

WScript.Quit

end if

'========== Проверка файла

Файлы в архиве Файлы9.rar. В архив я еще включил 2 файла скрипта с разным алгоритмом построения решения. Это файлы которые переводят данные из текстового файла в dbf. Они по действию подходят к файлам для статьи 8. Это файлы AdoED8Z.vbs и AdoED8U.vbs Файлы можно редактировать, а также переделать на JScript. Попробуйте Сами отработать большой dbf файл. И если Вам это тема интересна можете написать свои впечатления и свои достижения внизу под этой статьей.

Ссылка на файл https://disk.yandex.ru/d/Hj_znyk1Y5zCjA

Подписывайтесь на мой канал и ставьте лайки.