!================================================================================== ! Класс для работы с CSV-файлами. ! Вячеслав Черников, г.Рязань, 2017г. !================================================================================== MEMBER INCLUDE('fsCSV.INC') INCLUDE('WINEQU.INC') MAP INCLUDE('BUILTINS.CLW'),ONCE !функции RTL MODULE('Windows API') CreateFile(*CSTRING,ULONG=GENERIC_READ+GENERIC_WRITE,ULONG=0,ULONG=0,ULONG=CREATE_ALWAYS,ULONG=FILE_FLAG_RANDOM_ACCESS,UNSIGNED=0),UNSIGNED,PASCAL,RAW,NAME('CreateFileA') CloseFile(UNSIGNED),SIGNED,PROC,PASCAL,NAME('CloseHandle') WriteFile(UNSIGNED,<*?>,ULONG,*ULONG,<*?>),BOOL,PASCAL,RAW,PROC ReadFile(UNSIGNED,LONG,ULONG,*ULONG,LONG),BOOL,PASCAL,RAW,NAME('ReadFile') CloseHandle(UNSIGNED),BOOL,PASCAL,PROC,NAME('CloseHandle') GetFileSize(UNSIGNED,*ULONG),ULONG,PASCAL,NAME('GetFileSize') END END FILE_ATTRIBUTE_NORMAL equate(00000080H) !=================================================================================== ! Инициализация класса ! FsCSV.Init PROCEDURE CODE if SELF.Active=1 return end SELF.Active=1 SELF.BufPoint =0 SELF.BufPointMax = 1024 SELF.StructFieldsMax = 100 SELF.QueueBuf &= new(QueueCSVType) !создание буфера SELF.QueueStructCSV &= new(QueueStructCSVType) !создание списка структур !=================================================================================== ! Деактивация класса ! FsCSV.Kill PROCEDURE CODE if SELF.Active=0 return end free(SELF.QueueBuf) free(SELF.QueueStructCSV) dispose(SELF.QueueBuf) dispose(SELF.QueueStructCSV) SELF.Active=0 !=================================================================================== ! ! Деструктор класса ! FsCSV.Destruct PROCEDURE CODE SELF.Kill !=================================================================================== ! ! Установить структуру группы ! FsCSV.SetStruct PROCEDURE (STRING pName, *QUEUE pQueue) loc:i long loc:str string(40) CODE if SELF.Active = 0 return end clear(SELF.QueueStructCSV) SELF.QueueStructCSV.StructName = lower(pName) get(SELF.QueueStructCSV,SELF.QueueStructCSV.StructName) if ~error() return end SELF.AddStrInt2('#' & lower(pName)) loc:i=0 loop loc:i+=1 if loc:i>SELF.StructFieldsMax break end loc:str=lower(who(pQueue,loc:i)) if loc:str='' break end SELF.QueueStructCSV.StructField[loc:i] &= what(pQueue,loc:i) SELF.AddStrInt2(',' & loc:str) end SELF.QueueStructCSV.StructFields = loc:i SELF.QueueStructCSV.StructRef &= pQueue add(SELF.QueueStructCSV,SELF.QueueStructCSV.StructName) SELF.AddStrInt2(CHR(13) & CHR(10)) !=================================================================================== ! ! Экспортировать группу ! FsCSV.ExportGroup PROCEDURE (STRING pName, *GROUP pGroup) loc:i long loc:zn any loc:str string(40) CODE if SELF.Active = 0 return end clear(SELF.QueueStructCSV) SELF.QueueStructCSV.StructName = lower(pName) get(SELF.QueueStructCSV,SELF.QueueStructCSV.StructName) if error() return end SELF.AddStrInt2(lower(pName)) loc:i=0 loop loc:i+=1 if loc:i>SELF.StructFieldsMax break end loc:str=lower(who(pGroup,loc:i)) if loc:str='' break end loc:zn &= what(pGroup,loc:i) SELF.QueueStructCSV.StructField[loc:i] = loc:zn SELF.AddStrInt2(',"' & clip(SELF.StrReplaceSpec(SELF.QueueStructCSV.StructField[loc:i])) & '"') end SELF.AddStrInt2(CHR(13) & CHR(10)) !=================================================================================== ! ! Экспортировать очередь ! FsCSV.ExportQueue PROCEDURE (STRING pName, *QUEUE pQueue) loc:i long CODE if SELF.Active = 0 return end clear(SELF.QueueStructCSV) SELF.QueueStructCSV.StructName = lower(pName) get(SELF.QueueStructCSV,SELF.QueueStructCSV.StructName) if error() return end if records(pQueue)=0 return end loop loc:i=1 to records(pQueue) get(pQueue,loc:i) SELF.ExportGroup(pName,pQueue) end !=================================================================================== ! ! Импортировать файл ! FsCSV.ImportFile PROCEDURE (STRING pName, BYTE pReg) ASCIIFile FILE,DRIVER('ASCII'),PRE(ARF),CREATE Record RECORD,PRE() rec STRING(4096) END END loc:i long loc:j long loc:p1 long loc:p2 long loc:num long loc:ok byte loc:zn string(40) loc:str string(40) loc:queue &queue CODE if SELF.Active = 0 return end if ~exists(pName) SELF.ErrorCode=1 SELF.ErrorMessage='Файл для загрузки не найден! - ' & clip(pName) return end SELF.FileNameCSV = pName ASCIIFile{PROP:NAME}=SELF.FileNameCSV open(ASCIIFile) if error() SELF.ErrorCode=error() SELF.ErrorMessage='Не могу открыть файл для загрузки - ' & clip(pName) return end set(ASCIIFile) loop next(ASCIIFile) if error() break end if sub(arf:rec,1,1)='#' !структура do loadStruct_r else if pReg=1 !только структуры break end do loadRec_r end end close(ASCIIFile) loadStruct_r routine !загрузить структуру loc:p1=instring(',',arf:rec,1,1) if loc:p1=0 exit end clear(SELF.QueueStructCSV) SELF.QueueStructCSV.StructName=lower(sub(arf:rec,2,loc:p1-2)) get(SELF.QueueStructCSV,SELF.QueueStructCSV.StructName) if error() exit end loc:queue &= SELF.QueueStructCSV.StructRef loc:j=0 loop loc:p2=instring(',',arf:rec,1,loc:p1+1) if loc:p2=0 loc:zn=sub(arf:rec,loc:p1+1,len(clip(arf:rec))-loc:p1) else loc:zn=sub(arf:rec,loc:p1+1,loc:p2-loc:p1-1) end loc:j+=1 loc:i=0 loop loc:i+=1 if loc:i>SELF.StructFieldsMax break end loc:str=lower(who(loc:queue,loc:i)) if loc:str='' break end if loc:str=loc:zn SELF.QueueStructCSV.StructNums[loc:j] = loc:i break end end if loc:p2=0 break end loc:p1=loc:p2 end put(SELF.QueueStructCSV) loadRec_r routine !загрузить запись arf:rec=left(arf:rec) loc:p1=instring(',',arf:rec,1,1) if loc:p1=0 exit end loc:ok=0 clear(SELF.QueueStructCSV) SELF.QueueStructCSV.StructName=lower(sub(arf:rec,1,loc:p1-1)) get(SELF.QueueStructCSV,SELF.QueueStructCSV.StructName) if error() exit end loc:j=0 loop loc:p2=instring(',',arf:rec,1,loc:p1+1) loc:j+=1 if loc:j>SELF.StructFieldsMax break end loc:num=SELF.QueueStructCSV.StructNums[loc:j] if loc:num=0 if loc:p2=0 break else cycle end end loc:ok=1 if loc:p2=0 SELF.QueueStructCSV.StructField[loc:num] = SELF.StrReplaceSpecImp(sub(arf:rec,loc:p1+1,len(clip(arf:rec))-loc:p1)) break else SELF.QueueStructCSV.StructField[loc:num] = SELF.StrReplaceSpecImp(sub(arf:rec,loc:p1+1,loc:p2-loc:p1-1)) end loc:p1=loc:p2 end if loc:ok=1 loc:queue &= SELF.QueueStructCSV.StructRef add(loc:queue) end !=================================================================================== ! ! Импортировать запись ! FsCSV.ImportRec FUNCTION (STRING Str) loc:j long loc:p1 long loc:p2 long loc:num long CODE if SELF.Active = 0 return('') end loc:p1=instring(',',Str,1,1) if loc:p1=0 return('') end clear(SELF.QueueStructCSV) SELF.QueueStructCSV.StructName=lower(sub(Str,1,loc:p1-1)) get(SELF.QueueStructCSV,SELF.QueueStructCSV.StructName) if error() return('') end loc:j=0 loop loc:p2=instring(',',Str,1,loc:p1+1) loc:j+=1 if loc:j>SELF.StructFieldsMax break end loc:num=SELF.QueueStructCSV.StructNums[loc:j] if loc:num=0 if loc:p2=0 break else cycle end end if loc:p2=0 SELF.QueueStructCSV.StructField[loc:num] = SELF.StrReplaceSpecImp(sub(Str,loc:p1+1,len(clip(Str))-loc:p1)) break else SELF.QueueStructCSV.StructField[loc:num] = SELF.StrReplaceSpecImp(sub(Str,loc:p1+1,loc:p2-loc:p1-1)) end loc:p1=loc:p2 end return(SELF.QueueStructCSV.StructName) !=================================================================================== ! ! Добавить строку в буфер ! FsCSV.AddStrInt PROCEDURE (STRING Str) loc:dl long loc:poz long CODE if SELF.Active = 0 return end loc:dl = len(clip(str))+2 loc:poz = 0 if (SELF.BufPoint+loc:dl)<=SELF.BufPointMax !вся строка помещается в строку буфера if SELF.BufPoint=0 SELF.QueueBuf = clip(str) & CHR(13) & CHR(10) else SELF.QueueBuf = sub(SELF.QueueBuf,1,SELF.BufPoint) & clip(str) & CHR(13) & CHR(10) end SELF.BufPoint += loc:dl return end if SELF.BufPoint>0 and (SELF.BufPoint+loc:dl)>=SELF.BufPointMax !дописываем последнюю строку в кьюшке скрипта SELF.QueueBuf = sub(SELF.QueueBuf,1,SELF.BufPoint) & sub(clip(str) & CHR(13) & CHR(10),1,SELF.BufPointMax-SELF.BufPoint) add(SELF.QueueBuf) loc:poz=SELF.BufPointMax-SELF.BufPoint SELF.BufPoint=0 end loop !вписываем целые части if loc:dl-loc:poz0 SELF.QueueBuf = sub(clip(str) & CHR(13) & CHR(10),loc:poz+1,loc:dl-loc:poz) SELF.BufPoint=loc:dl-loc:poz end !=================================================================================== ! ! Добавить фрагмент строки в буфер ! FsCSV.AddStrInt2 PROCEDURE (STRING Str) loc:dl long loc:poz long CODE if SELF.Active = 0 return end loc:dl = len(clip(str)) loc:poz = 0 if (SELF.BufPoint+loc:dl)<=SELF.BufPointMax !вся строка помещается в строку буфера if SELF.BufPoint=0 SELF.QueueBuf = clip(str) else SELF.QueueBuf = sub(SELF.QueueBuf,1,SELF.BufPoint) & clip(str) end SELF.BufPoint += loc:dl return end if SELF.BufPoint>0 and (SELF.BufPoint+loc:dl)>=SELF.BufPointMax !дописываем последнюю строку в кьюшке скрипта SELF.QueueBuf = sub(SELF.QueueBuf,1,SELF.BufPoint) & sub(clip(str),1,SELF.BufPointMax-SELF.BufPoint) add(SELF.QueueBuf) loc:poz=SELF.BufPointMax-SELF.BufPoint SELF.BufPoint=0 end loop !вписываем целые части if loc:dl-loc:poz0 SELF.QueueBuf = sub(clip(str),loc:poz+1,loc:dl-loc:poz) SELF.BufPoint=loc:dl-loc:poz end !=================================================================================== ! Сформировать файл ! FsCSV.MakeFile PROCEDURE (STRING pName) loc:LocalFile CSTRING(255) !имя локального файла loc:hLocal UNSIGNED !ссылка на локальный файл loc:BufferLength ULONG loc:Buffer &CSTRING loc:recs long loc:len long loc:i long loc:err byte CODE if SELF.Active=0 return end if pName='' message('Не задано имя csv-файла!') return end if exists(pName) remove(pName) end SELF.FileNameCSV = pName loc:len=len(SELF.QueueBuf) loc:recs=records(SELF.QueueBuf) if loc:recs=0 and SELF.BufPoint=0 return end if SELF.BufPoint<>0 add(SELF.QueueBuf) end loc:BufferLength = loc:len*loc:recs+SELF.BufPoint+1 loc:Buffer &= new(CSTRING(loc:BufferLength)) loop loc:i=1 to records(SELF.QueueBuf) get(SELF.QueueBuf,loc:i) if loc:i=1 loc:Buffer=SELF.QueueBuf else loc:Buffer=sub(loc:Buffer,1,loc:len*(loc:i-1)) & SELF.QueueBuf end end loc:LocalFile = SELF.FileNameCSV loc:hLocal = CreateFile(loc:LocalFile, GENERIC_READ+GENERIC_WRITE, | !создать ссылку на выходной файл FILE_SHARE_READ + FILE_SHARE_WRITE, 0 , | CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,0) if ~WriteFile(loc:hLocal, loc:Buffer, loc:BufferLength, loc:BufferLength) loc:err=1 else loc:err=0 end CloseHandle(loc:hLocal) !закрываем выходной файл clear(loc:Buffer) dispose(loc:Buffer) free(SELF.QueueBuf) if loc:err=1 SELF.ErrorCode = 2 SELF.ErrorMessage = 'Ошибка при сохранении в файл ' & clip(SELF.FileNameCSV) message(SELF.ErrorMessage) end !=================================================================================== ! Замена символов в строке ! FsCSV.StrReplace FUNCTION (STRING Str, STRING StrSource, STRING StrTarg) loc:strRet string(4096) loc:k long loc:p long CODE if StrSource=StrTarg !проверка на совпадение исходной и целевой подстроки return(Str) end loc:StrRet=Str loc:k=0 loop loc:p=instring(StrSource,clip(loc:strRet),1,loc:k+1) if loc:p=0 break end Loc:StrRet=sub(loc:strRet,1,loc:p-1) & StrTarg & sub(loc:StrRet,loc:p+len(StrSource),len(clip(Loc:StrRet))-loc:p-len(StrSource)+1) loc:k=loc:p+len(StrTarg)-len(StrSource) end return(loc:strRet) !=================================================================================== ! Замена специальных символов в строке (экспорт) ! FsCSV.StrReplaceSpec FUNCTION (STRING Str) loc:strRet string(4096) loc:dl long loc:i long loc:k long CODE loc:dl=len(clip(Str)) loc:k=0 loop loc:i=1 to loc:dl case Str[loc:i] of '"' loc:k+=1 loc:strRet[loc:k]='"' loc:k+=1 loc:strRet[loc:k]='"' of CHR(13) loc:k+=1 loc:strRet[loc:k]='@' loc:k+=1 loc:strRet[loc:k]='`' loc:k+=1 loc:strRet[loc:k]='3' of CHR(10) loc:k+=1 loc:strRet[loc:k]='@' loc:k+=1 loc:strRet[loc:k]='`' loc:k+=1 loc:strRet[loc:k]='0' else loc:k+=1 loc:strRet[loc:k]=Str[loc:i] end end return(loc:strRet) !=================================================================================== ! Замена специальных символов в строке (импорт) ! FsCSV.StrReplaceSpecImp FUNCTION (STRING Str) loc:strRet string(4096) CODE if sub(Str,1,1)='"' and sub(Str,len(clip(Str)),1)='"' loc:strRet = sub(Str,2,len(clip(Str))-2) else loc:strRet = Str end loc:strRet=SELF.StrReplace(loc:strRet,'""','"') loc:strRet=SELF.StrReplace(loc:strRet,'@`0',CHR(10)) loc:strRet=SELF.StrReplace(loc:strRet,'@`3',CHR(13)) return(loc:strRet)