码迷,mamicode.com
首页 > 编程语言 > 详细

VBA CSV格式的解析类 【c语言CSV Parser转换】

时间:2015-01-12 06:44:27      阅读:309      评论:0      收藏:0      [点我收藏+]

标签:

技术分享
  1 Option Explicit
  2 ----------------读Csv文件 类---------------------
  3 
  4 Private Declare Function WideCharToMultiByte Lib "kernel32" _
  5     (ByVal CodePage As Long, _
  6      ByVal dwFlags As Long, _
  7      ByVal lpWideCharStr As Long, _
  8      ByVal cchWideChar As Long, _
  9      ByRef lpMultiByteStr As Any, _
 10      ByVal cchMultiByte As Long, _
 11      ByVal lpDefaultChar As String, _
 12      ByVal lpUsedDefaultChar As Long) As Long
 13 
 14 Private Declare Function MultiByteToWideChar Lib "kernel32" _
 15     (ByVal CodePage As Long, _
 16      ByVal dwFlags As Long, _
 17      ByRef lpMultiByteStr As Any, _
 18      ByVal cchMultiByte As Long, _
 19      ByVal lpWideCharStr As Long, _
 20      ByVal cchWideChar As Long) As Long
 21      
 22 Private Type BuffType 一个缓冲区
 23     StartPosAbso As Long 该缓冲区在文件中的绝对位置
 24     BufLen As Long  缓冲区总长
 25     PtrInBuf As Long 缓冲区内部指针
 26     ptrNextStrStartInBuf As Long 下一行内容开始位置(从此处算到下一个cr/lf为下一行)
 27     IgnoreFirstLf As Boolean 是否忽略本缓冲区的第一个 vblf
 28     bufBytes() As Byte 缓冲区内容(字节数组)
 29 End Type
 30 
 31 
 32 Dim State As StateType
 33 Private Enum StateType
 34     NewFieldStart
 35     NonQuotesField
 36     QuotesField
 37     FieldSeparator
 38     QuoteInQuotesField
 39     RowSeparator
 40     ErrorS
 41 End Enum
 42 
 43 Dim af_Buff As BuffType 一个缓冲区
 44 Dim af_lngFileLength As Long
 45 
 46 Dim lFileName As String
 47 Dim lFileNum As Integer
 48 Dim lStatus As Integer -1=已关闭;1=已打开;2=已经开始读取;0=未设
 49 Dim lIsEndRead As Boolean =true表示或者读完文件或者出错,即不能再继续读了,主程序应退出读取
 50 Dim lErrOccured As Boolean 是否上次 GetNextLine 发生了一个错误
 51 Dim lAutoOpen As Boolean 是否设置 FileName 属性时自动打开文件,默认为true(类初始化时设为true)
 52 Dim lAutoClose As Boolean 是否 读取行读完文件或出错时 自动关闭文件,默认为true(类初始化时设为true)
 53 
 54 
 55 
 56 
 57 Dim lEncode As Long 编码设置
 58 Dim EncodeErr As Boolean 编码转换时出错Flag
 59 Public Enum EncodeEnum
 60     Default = 0
 61     ShifJis = 932
 62     JIS = 50220
 63     Utf8 = 65001
 64     GB2312 = 936
 65 End Enum
 66 
 67 
 68 Dim ch As Long
 69 以上仅为GetNextLine函数用,为了不每次调用GetNextLine时候都重新定义,故将之做为全局的了,其实应是局部的
 70 _______________________________________
 71 Dim lineArr As New Collection
 72 Dim strArr() As Byte
 73 Dim strArrlBuff As Long
 74 Private Const mcInitBuffSize As Long = 100 初始分配空间大小,10K
 75 
 76 Public Function GetNextLine(ByRef col As Collection) As Integer
 77     读取文件的下一行文本,支持 vbCrLf、vbLf、vbCr 的多种分行符
 78     返回1表示正常读取了
 79     返回-1也表示正常,但读完了文件
 80     返回0表示出错或非法
 81     1. 一般出错返回0,并设置 lErrOccured=True
 82     2. 如果上次读完了文件,则允许再额外调用一次 GetNextLine (返回 0 并 _
 83       不提示出错,lErrOccured 仍为 false,此算非法);如果再调用就出错了 _
 84       (函数仍返回0,但 lErrOccured 为 true 此算出错)
 85 
 86 
 87     设置反映错误的标志变量
 88     lErrOccured = False 表示尚未发生错误;如后续程序中发生了错误再改为 True
 89     判断和设置状态
 90     If lStatus = 0 Then
 91         lStatus = 0:当前状态非法,尚未打开文件,无法读取
 92         GoTo errExit
 93     ElseIf lStatus < 0 Then
 94         GoTo errExit 不允许额外调用了,出错
 95     End If
 96     
 97     正常读取的情况:此时 lStatus 要么为1要么为2,即要么文件已经打开, _
 98       要么已经进入读取状态了,总之读取下一行是没有问题的
 99     lStatus = 2 设置为2表示已经进入读取状态
100     
101     
102     //////////////// 读取文件,以找到“一行”的内容 ////////////////
103     On Error GoTo errExit  有任何错误发生时都转到errExit标签处执行
104     
105     With af_Buff
106         缓冲区逐渐沿文件前进,直到缓冲区起始位置超过文件总长读完文件
107         Do Until .StartPosAbso > af_lngFileLength
108         
109             ============ (1)根据需要读取文件的下一个缓冲区内容 ============
110             若 .PtrInBuf=-1 表示要读取下一个缓冲区,否则不读取下一个,仍使用 _
111               当前缓冲区和 .PtrInBuf 指针
112             If .PtrInBuf < 0 Then
113                 ----从 .StartPosAbso 开始读取一些字节存入缓冲区 .bufBytes()
114                 .BufLen = FileGetBytesLocal(.StartPosAbso, .bufBytes())
115                 If .BufLen <= 0 Then GoTo errExit 读取出错
116                 
117                 ----初始化缓冲区指针
118                 .PtrInBuf = 1
119                 看是否需要忽略第一个 vbLf
120                 If .IgnoreFirstLf Then
121                     If .bufBytes(.PtrInBuf) = 10 Then 第1个字节确是 vbLf
122                         忽略第一个 vbLf
123                         .PtrInBuf = .PtrInBuf + 1
124                     End If If .bufBytes(.PtrInBuf) = 10 Then
125                     
126                     .IgnoreFirstLf = False 恢复标志,不忽略第一个 vbLf
127                 End If If .IgnoreFirstLf Then
128                 
129                 初始化下一行起始位置 ptrNextStrStartInBuf (下一行内容包含该字节)
130                 .ptrNextStrStartInBuf = .PtrInBuf
131             End If If .PtrInBuf < 0 Then
132             
133             ============ (2)逐个扫描缓冲区中的字节,查找分行符 ============
134             扫描缓冲区中的字节,直到找到 vbCr或vbLf 或扫描完缓冲区
135             For .PtrInBuf = .PtrInBuf To .BufLen
136                 ch = .bufBytes(.PtrInBuf)
137                 Select Case State 34代表双引号 44代表逗号
138                     Case NewFieldStart
139                         If ch = 34 Then
140                             State = QuotesField
141                         ElseIf ch = 44 Then
142                             lineArr.Add ""
143                             State = FieldSeparator
144                         ElseIf ch = 13 Or ch = 10 Then
145                             State = NewFieldStart
146                             Exit For
147                         Else
148 
149                             strArrlBuff = strArrlBuff + 1
150                             If strArrlBuff Mod mcInitBuffSize = 0 Then
151                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
152                             End If
153                             ReDim Preserve strArr(1 To strArrlBuff)
154                             strArr(strArrlBuff) = ch
155                             strArr.Add ch
156                             State = NonQuotesField
157                         End If
158                     Case NonQuotesField
159                         If ch = 44 Then
160                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
161                             Erase strArr
162                             ReDim strArr(1 To mcInitBuffSize)
163                             strArrlBuff = 0
164                             Set strArr = New Collection
165                             State = FieldSeparator
166                         ElseIf ch = 13 Then
167                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
168                             State = RowSeparator
169                         Else
170                             strArrlBuff = strArrlBuff + 1
171                             If strArrlBuff Mod mcInitBuffSize = 0 Then
172                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
173                             End If
174                             ReDim Preserve strArr(1 To strArrlBuff)
175                             strArr(strArrlBuff) = ch
176                             strArr.Add ch
177                         End If
178                     Case QuotesField
179                         If ch = 34 Then
180                             State = QuoteInQuotesField
181                         Else
182                             strArrlBuff = strArrlBuff + 1
183                             If strArrlBuff Mod mcInitBuffSize = 0 Then
184                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
185                             End If
186                             ReDim Preserve strArr(1 To strArrlBuff)
187                             strArr(strArrlBuff) = ch
188                             strArr.Add ch
189                         End If
190                     Case FieldSeparator
191                         If ch = 44 Then
192                             lineArr.Add ""
193                         ElseIf ch = 34 Then
194                             Erase strArr
195                             ReDim strArr(1 To mcInitBuffSize)
196                             strArrlBuff = 0
197                             Set strArr = New Collection
198                             State = QuotesField
199                         ElseIf ch = 13 Then
200                             lineArr.Add ""
201                             State = RowSeparator
202                         Else
203                             strArrlBuff = strArrlBuff + 1
204                             If strArrlBuff Mod mcInitBuffSize = 0 Then
205                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
206                             End If
207                             ReDim Preserve strArr(1 To strArrlBuff)
208                             strArr(strArrlBuff) = ch
209                             strArr.Add ch
210                             State = NonQuotesField
211                         End If
212                     Case QuoteInQuotesField
213                         If ch = 44 Then
214                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
215                             Erase strArr
216                             ReDim strArr(1 To mcInitBuffSize)
217                             strArrlBuff = 0
218                             Set strArr = New Collection
219                             State = FieldSeparator
220                         ElseIf ch = 13 Then
221                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
222                             State = RowSeparator
223                         ElseIf ch = 34 Then
224                             strArrlBuff = strArrlBuff + 1
225                             If strArrlBuff Mod mcInitBuffSize = 0 Then
226                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
227                             End If
228                             ReDim Preserve strArr(1 To strArrlBuff)
229                             strArr(strArrlBuff) = ch
230                             strArr.Add ch
231                             State = QuotesField
232                         Else
233                             State = ErrorS "语法错误: 转义字符 \" 不能完成转义 或 引号字段结尾引号没有紧贴字段分隔符";
234                         End If
235                     Case RowSeparator
236                         If ch = 10 Then
237                             Erase strArr
238                             ReDim strArr(1 To mcInitBuffSize)
239                             strArrlBuff = 0
240                             Set strArr = New Collection
241                             State = NewFieldStart
242                             Exit For
243                         Else
244                             State = ErrorS "语法错误: 行分隔用了回车 \\r。但未使用回车换行 \\r\\n ";
245                         End If
246                     Case ErrorS
247                         GoTo errExit
248                                             
249                 End Select
250 
251                 If .bufBytes(.PtrInBuf) = 13 Or _
252                  .bufBytes(.PtrInBuf) = 10 Then Exit For
253             Next .PtrInBuf
254             
255             退出 For 后,判断是否找到了分行符 vbCr或vbLf
256             If .PtrInBuf <= .BufLen Then  是否找到了 vbCr或vbLf
257                 If .PtrInBuf + 1 > .BufLen And _
258                   .StartPosAbso + .BufLen > af_lngFileLength Then
259                     已经读完文件
260                     lIsEndRead = True
261                     If lAutoClose Then CloseFile
262                 Else
263                     还未读完文件,再判断是否文件只剩一个字节;若只剩一个字节并且 _
264                       剩下的正好是 vbLf,并且下次要忽略掉 vbLf,则仍是已经读完文件
265                     If .StartPosAbso + .BufLen = af_lngFileLength And .IgnoreFirstLf Then
266                         读取文件中的最后一个字节,只测试一下
267                         Dim tByt() As Byte, tRet As Integer
268                         tRet = FileGetBytesLocal(.StartPosAbso + .BufLen, tByt())
269                         If tRet <= 0 Then GoTo errExit 出错处理
270                         If tByt(1) = 10 Then
271                             已经读完文件
272                             lIsEndRead = True
273                             If lAutoClose Then CloseFile
274                         End If
275                     End If
276                 End If
277                 .PtrInBuf = .PtrInBuf + 1
278             
279                 If lIsEndRead Then
280                     已经读完文件,一定 Exit Function
281                     
282                     Set col = lineArr
283                     Set lineArr = New Collection
284                     strArrlBuff = 0
285                     GetNextLine = 0
286                     
287                     Exit Function 已经读完文件,一定 Exit Function
288                 Else If lIsEndRead Then
289                     没有读完文件(忽略空行不退出,否则退出)
290                         If GetNextLine = 0 Then
291                         不需要忽略空行或最后不是空行,退出
292                         Else
293                             Set col = lineArr
294                             Set lineArr = New Collection
295                             strArrlBuff = 0
296                             GetNextLine = 1
297                             Exit Function
298                         End If
299                 End If If lIsEndRead Then
300                 
301             Else If .PtrInBuf <= .BufLen Then ‘是否找到了 vbCr或vbLf
302                  
303                  .PtrInBuf = -1
304                 ==== 准备继续读下一个缓冲区 ====
305                 .StartPosAbso = .StartPosAbso + .BufLen
306             End If If .PtrInBuf <= .BufLen Then ‘是否找到了 vbCr或vbLf
307         Loop
308     End With
309     
310     
311     //////////// 全部读完文件,看还有无剩余的 ////////////
312    
313         
314         Select Case State
315             Case NonQuotesField
316                  lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
317                  Erase strArr
318                  ReDim strArr(1 To mcInitBuffSize)
319                  strArrlBuff = 0
320                  lineArr.Add strArr
321                  Set strArr = New Collection
322             Case QuotesField
323                  GoTo errExit "语法错误: 引号字段未闭合";
324             Case FieldSeparator
325                 lineArr.Add ""
326             Case QuoteInQuotesField
327                 lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
328                 
329         End Select
330         
331 
332         Set col = lineArr
333         Set lineArr = New Collection
334         strArrlBuff = 0
335 
336         GetNextLine = 0
337 
338         
339         If lAutoClose Then CloseFile
340         lIsEndRead = True
341         此时读完文件,必须返回
342         Exit Function
343 
344     
345 
346 errExit:
347     lErrOccured = True
348     GetNextLine = 0
349     为一般错误,不设置 lIsEndRead = True
350     If lAutoClose Then CloseFile
351 End Function
352 
353 Private Function EncodeStr(ByRef bytIn() As Byte, hasError As Boolean, Optional byteSize As Long = -1) As String
354 
355     Select Case Encode
356         Case Default
357             Dim tempStr As String
358             tempStr = bytIn
359             EncodeStr = StrConv(tempStr, vbUnicode)
360 
361         Case ShifJis
362             EncodeStr = WCMB_Decode(ShifJis, bytIn, hasError, byteSize)
363         Case JIS
364              EncodeStr = WCMB_Decode(JIS, bytIn, hasError, byteSize)
365         Case Utf8
366             EncodeStr = WCMB_Decode(Utf8, bytIn, hasError, byteSize)
367         Case GB2312
368              EncodeStr = WCMB_Decode(GB2312, bytIn, hasError, byteSize)
369     End Select
370 
371 End Function
372 
373 
374  関数名    : WCMB_Decode
375  返り値    : UNICODE文字列
376  引き数    : cp    : 入力文字データのコードページ番号
377            : bytIn : 入力文字データ
378  機能説明  : 入力文字データをUNICODEに変換する
379  備考      : MultiByteToWideCharによる文字コード変換
380 Private Function WCMB_Decode(ByVal cp As Long, ByRef bytIn() As Byte, ByRef hasError As Boolean, Optional byteSize As Long = -1) As String
381     On Error GoTo ErrHandler
382 
383     Dim lngInSize As Long
384     Dim strBuf As String
385     Dim lngBufLen As Long
386     Dim lngRtn As Long
387     If byteSize > 0 Then
388         lngInSize = byteSize
389     Else
390         If bytIn(UBound(bytIn)) = 13 Then
391             lngInSize = UBound(bytIn) - 1
392         Else
393             lngInSize = UBound(bytIn)
394         End If
395     End If
396     lngBufLen = (lngInSize + 1) * 5
397     strBuf = String$(lngBufLen, vbNullChar)
398     lngRtn = MultiByteToWideChar _
399         (cp, 0, bytIn(1), lngInSize, StrPtr(strBuf), lngBufLen)
400     If lngRtn Then
401         WCMB_Decode = Left$(strBuf, lngRtn)
402     End If
403     hasError = False
404     Exit Function
405 ErrHandler:
406     WCMB_Decode = ""
407     hasError = True
408 End Function
409 
410 Public Sub Init()
411 
412     ReDim strArr(1 To mcInitBuffSize) CSV 各个单元 缓冲区
413     strArrlBuff = 0
414                  
415     Erase af_Buff.bufBytes 缓冲区
416     
417     
418 
419     af_lngFileLength = 0
420     af_Buff.StartPosAbso = 1 当前缓冲区的起始处所在的文件位置
421     af_Buff.ptrNextStrStartInBuf = 1
422     
423     此作为标志,=-1表示下次运行 GetNextLine 要重新读取新的缓冲区 _
424       否则不重新读取,仍使用当前缓冲区和 .PtrInBuf 指针
425     af_Buff.PtrInBuf = -1
426     
427     lErrOccured = False
428 
429     
430     af_Buff.IgnoreFirstLf = False 初始化标志:当前缓冲区不需要忽略第一个字节(若是vblf)
431     
432     lIsEndRead = False
433 End Sub
434 
435 Public Function GetPercent(Optional DotNum As Integer = 2) As Single
436     DotNum保留几位小数,<0或>7为不保留小数
437     Dim sngPerc As Single
438     
439     If af_lngFileLength > 0 Then
440         If af_Buff.PtrInBuf < 0 Then
441             sngPerc = (af_Buff.StartPosAbso - 1) / af_lngFileLength
442         Else
443             sngPerc = (af_Buff.StartPosAbso + af_Buff.PtrInBuf - 2) / af_lngFileLength
444         End If
445     End If
446     
447     If DotNum >= 0 Or DotNum <= 7 Then
448         Dim Temp As Long
449         Temp = 10 ^ DotNum
450         sngPerc = Int(Temp * sngPerc + 0.5) / Temp
451     End If
452     
453     GetPercent = sngPerc
454 End Function
455 
456 Public Sub CloseFile()
457     If lFileNum > 0 Then Close lFileNum: lFileNum = 0
458     lStatus = -1 表示文件已关闭
459     不Init,防止读取行后自动关闭文件时状态变量被初始化;在OpenFile时会Init
460 End Sub
461 
462 Public Function OpenFile() As Boolean
463     If lFileNum > 0 Then CloseFile 如果已打开了文件,则先关闭它
464     lFileNum = FreeFile 获得一个可用的文件号(同时属性 FileNum 的值也自动改变)
465     On Error GoTo errH 如果一下程序发生任何错误,就转到 errH 标签处执行
466     If Dir(lFileName, 31) = "" Then GoTo errH 如果文件不存在,就转到 errH 标签处执行
467     Open lFileName For Binary Access Read As #lFileNum 以二进制方式打开文件
468     lStatus = 1 表示文件已打开
469     Init 初始化操作
470     af_lngFileLength = LOF(lFileNum) 设置文件总大小
471     OpenFile = True
472     Exit Function
473 errH:
474     If lFileNum > 0 Then CloseFile
475     OpenFile = False
476 End Function
477 
478 
479 
480 Private Function FileGetBytesLocal(ByVal ReadPos As Long, _
481                                          ArrBytes() As Byte, _
482                           Optional ByVal EndingBorder As Long = 0, _
483                           Optional ByVal ReadMax As Long = 16384) As Long
484                           Optional ByVal ReadMax As Long = 16384, _
485     从文件号 lFileNum 中的 ReadPos 位置开始读取一批字节
486     从参数ArrBytes()返回读取的字节内容,会重新定义ArrBytes()数组
487     所读取的字节数不确定,如果文件中有足够的内容,就读取ReadMax个字节, _
488       否则就读到文件尾(当EndingBorder参数<=0时)或读到EndingBorder _
489       为止(当EndingBorder参数>0时)
490     ShowResume 指定如果读取出错,是否弹出对话框提示
491       若ShowResume=1,提示框中有"重试"和"取消"两个按钮;
492       若ShowResume=2,出错时提示框中有"终止"、"重试"和"忽略"三个按钮;
493       若ShowResume=0,出错时不弹出提示框,不弹出提示框就不能在发生错误时重试
494     返回读取的字节数,若失败返回<=0,若用户“忽略”则返回=0;_
495       若用户终止或取消或无提示框,则返回<0
496     
497     Dim lngUBound As Long
498     
499     If EndingBorder <= 0 Then EndingBorder = LOF(lFileNum)
500     If EndingBorder < ReadPos Then
501         FileGetBytesLocal = -1
502         Exit Function
503     End If
504     
505     On Error GoTo errH
506     If EndingBorder - ReadPos + 1 >= ReadMax Then lngUBound = ReadMax Else _
507       lngUBound = EndingBorder - ReadPos + 1
508     
509     ReDim ArrBytes(1 To lngUBound) As Byte
510     
511     Get #FileNum, ReadPos, ArrBytes
512 
513     FileGetBytesLocal = lngUBound
514     Exit Function
515 errH:
516      FileGetBytesLocal = -1
517 End Function
518 
519 
520 
521 Private Sub Class_Initialize()
522     lAutoOpen = True 设置 FileName 属性时自动打开文件
523     lAutoClose = True 读取行读完文件或出错时 自动关闭文件
524 End Sub
525 
526 Private Sub Class_Terminate()
527     CloseFile
528     Erase af_Buff.bufBytes
529 
530 End Sub
531 
532 
533 Public Property Get FileName() As String
534     FileName = lFileName
535 End Property
536 
537 Public Property Let FileName(ByVal vNewValue As String)
538     If lFileNum > 0 Then CloseFile
539     lFileName = vNewValue
540     If lAutoOpen Then OpenFile
541 End Property
542 
543 Public Property Get FileNum() As Integer
544     FileNum = lFileNum
545 End Property
546 
547 Public Property Get Status() As Integer
548     Status = lStatus
549 End Property
550 
551 Public Property Get IsEndRead() As Boolean
552     IsEndRead = lIsEndRead
553 End Property
554 
555 Public Property Get AutoOpen() As Boolean
556     AutoOpen = lAutoOpen
557 End Property
558 
559 Public Property Let AutoOpen(ByVal vNewValue As Boolean)
560     lAutoOpen = vNewValue
561 End Property
562 
563 Public Property Get AutoClose() As Boolean
564     AutoClose = lAutoClose
565 End Property
566 
567 Public Property Let AutoClose(ByVal vNewValue As Boolean)
568     lAutoClose = vNewValue
569 End Property
570 
571 
572 Public Property Get ErrOccured() As Boolean
573     ErrOccured = lErrOccured
574 End Property
575 
576 Public Property Let ErrOccured(ByVal vNewValue As Boolean)
577     lErrOccured = vNewValue
578 End Property
579 
580 Public Property Get Encode() As EncodeEnum
581     Encode = lEncode
582 End Property
583 
584 Public Property Let Encode(ByVal vNewValue As EncodeEnum)
585     lEncode = vNewValue
586 End Property
587 
588 Public Property Get IsEncodeErr() As Boolean
589     IsEncodeErr = EncodeErr
590 End Property
只解析Item

 

技术分享
  1 Option Explicit
  2 ----------------读Csv文件 类---------------------
  3 
  4 Private Declare Function WideCharToMultiByte Lib "kernel32" _
  5     (ByVal CodePage As Long, _
  6      ByVal dwFlags As Long, _
  7      ByVal lpWideCharStr As Long, _
  8      ByVal cchWideChar As Long, _
  9      ByRef lpMultiByteStr As Any, _
 10      ByVal cchMultiByte As Long, _
 11      ByVal lpDefaultChar As String, _
 12      ByVal lpUsedDefaultChar As Long) As Long
 13 
 14 Private Declare Function MultiByteToWideChar Lib "kernel32" _
 15     (ByVal CodePage As Long, _
 16      ByVal dwFlags As Long, _
 17      ByRef lpMultiByteStr As Any, _
 18      ByVal cchMultiByte As Long, _
 19      ByVal lpWideCharStr As Long, _
 20      ByVal cchWideChar As Long) As Long
 21      
 22 Private Type BuffType 一个缓冲区
 23     StartPosAbso As Long 该缓冲区在文件中的绝对位置
 24     BufLen As Long  缓冲区总长
 25     PtrInBuf As Long 缓冲区内部指针
 26     ptrNextStrStartInBuf As Long 下一行内容开始位置(从此处算到下一个cr/lf为下一行)
 27     IgnoreFirstLf As Boolean 是否忽略本缓冲区的第一个 vblf
 28     bufBytes() As Byte 缓冲区内容(字节数组)
 29 End Type
 30 
 31 Private Type LastBuffType 缓冲区剩余的字节
 32     LeftBytes() As Byte
 33     LeftBLen As Long
 34 End Type
 35 
 36 Dim State As StateType
 37 Private Enum StateType
 38     NewFieldStart
 39     NonQuotesField
 40     QuotesField
 41     FieldSeparator
 42     QuoteInQuotesField
 43     RowSeparator
 44     ErrorS
 45 End Enum
 46 
 47 Dim af_Buff As BuffType 一个缓冲区
 48 Dim af_LastBuff As LastBuffType 缓冲区剩余的字节
 49 Dim af_OneEndRead As Boolean 是否在关闭文件后还允许再调用一次 GetNextLine
 50 Dim af_lngFileLength As Long
 51 
 52 Dim lFileName As String
 53 Dim lFileNum As Integer
 54 Dim lStatus As Integer -1=已关闭;1=已打开;2=已经开始读取;0=未设
 55 Dim lIsEndRead As Boolean =true表示或者读完文件或者出错,即不能再继续读了,主程序应退出读取
 56 Dim lErrOccured As Boolean 是否上次 GetNextLine 发生了一个错误
 57 Dim lTrimSpaces As Boolean
 58 Dim lAutoOpen As Boolean 是否设置 FileName 属性时自动打开文件,默认为true(类初始化时设为true)
 59 Dim lAutoClose As Boolean 是否 读取行读完文件或出错时 自动关闭文件,默认为true(类初始化时设为true)
 60 Dim lIgnoreEmpty As Boolean 是否自动忽略空行(注意:如果是最后一行仍可能返回空行)
 61 
 62 Dim lEndLineSign As Integer    行的结束标志:0=未设。13,10 or 2573(vbcrlf) ;-1:unknown(此时再次调用GetNextLine后看EndLineSignLast获得);-2:未知,读到文件末尾,文件末尾无换行符
 63 Dim lEndLineSignLast As Integer  上一行的结束标志 0=未设
 64 
 65 Dim lEncode As Long 编码设置
 66 Dim EncodeErr As Boolean 编码转换时出错Flag
 67 Public Enum EncodeEnum
 68     Default = 0
 69     ShifJis = 932
 70     JIS = 50220
 71     Utf8 = 65001
 72     GB2312 = 936
 73 End Enum
 74 
 75 
 76 Dim af_strBuf As String
 77 Dim af_bytsBuf() As Byte
 78 Dim j As Long
 79 Dim ch As Long
 80 以上仅为GetNextLine函数用,为了不每次调用GetNextLine时候都重新定义,故将之做为全局的了,其实应是局部的
 81 _______________________________________
 82 Dim lineArr As New Collection
 83 Dim strArr() As Byte
 84 Dim strArrlBuff As Long
 85 Private Const mcInitBuffSize As Long = 100 初始分配空间大小,10K
 86 
 87 Public Function GetNextLine(ByRef RetString As String, ByRef col As Collection) As Integer
 88     读取文件的下一行文本,支持 vbCrLf、vbLf、vbCr 的多种分行符
 89     返回1表示正常读取了
 90     返回-1也表示正常,但读完了文件
 91     返回0表示出错或非法
 92     1. 一般出错返回0,并设置 lErrOccured=True
 93     2. 如果上次读完了文件,则允许再额外调用一次 GetNextLine (返回 0 并 _
 94       不提示出错,lErrOccured 仍为 false,此算非法);如果再调用就出错了 _
 95       (函数仍返回0,但 lErrOccured 为 true 此算出错)
 96     3. lIgnoreEmpty=True 时自动忽略空行,如果从当前一直读到文件结束 _
 97       都是空行,则都忽略,并返回0(此时 lErrOccured=false,此算非法)
 98     只有要设置 lErrOccured=true 才会在 lShowMsgIfErrRead=true 时给出出错提示
 99     
100     
101     设置 反映分行符的 lEndLineSign 和 lEndLineSignLast 标志变量
102     lEndLineSignLast = lEndLineSign 将上一行的分行符更新为当前行的分行符
103     lEndLineSign = 0 将当前行的分行符先设为0,在后面程序读完本行后再具体设置
104     设置反映错误的标志变量
105     lErrOccured = False 表示尚未发生错误;如后续程序中发生了错误再改为 True
106     判断和设置状态
107     If lStatus = 0 Then
108         lStatus = 0:当前状态非法,尚未打开文件,无法读取
109         GoTo errExit
110     ElseIf lStatus < 0 Then
111         lStatus<0:表示此时文件尚未被打开,或者被强制关闭,或者已经读完文件 _
112           被自动关闭,总之是不能再继续读取文件了
113         若文件已读取完毕,允许再额外地调用一次GetNextLine方法
114         If af_OneEndRead Then 允许额外调用一次
115             af_OneEndRead = False 设置标志为 False,不允许再额外调用
116             GetNextLine = 0 不出错,但返回0
117             Exit Function 此时 lErrOccured 仍为 False
118         End If
119         GoTo errExit 不允许额外调用了,出错
120     End If
121     
122     正常读取的情况:此时 lStatus 要么为1要么为2,即要么文件已经打开, _
123       要么已经进入读取状态了,总之读取下一行是没有问题的
124     lStatus = 2 设置为2表示已经进入读取状态
125     
126     
127     //////////////// 读取文件,以找到“一行”的内容 ////////////////
128     On Error GoTo errExit  有任何错误发生时都转到errExit标签处执行
129     
130     With af_Buff
131         缓冲区逐渐沿文件前进,直到缓冲区起始位置超过文件总长读完文件
132         Do Until .StartPosAbso > af_lngFileLength
133         
134             ============ (1)根据需要读取文件的下一个缓冲区内容 ============
135             若 .PtrInBuf=-1 表示要读取下一个缓冲区,否则不读取下一个,仍使用 _
136               当前缓冲区和 .PtrInBuf 指针
137             If .PtrInBuf < 0 Then
138                 ----从 .StartPosAbso 开始读取一些字节存入缓冲区 .bufBytes()
139                 .BufLen = FileGetBytesLocal(.StartPosAbso, .bufBytes())
140                 If .BufLen <= 0 Then GoTo errExit 读取出错
141                 
142                 ----初始化缓冲区指针
143                 .PtrInBuf = 1
144                 看是否需要忽略第一个 vbLf
145                 If .IgnoreFirstLf Then
146                     If .bufBytes(.PtrInBuf) = 10 Then 第1个字节确是 vbLf
147                         忽略第一个 vbLf
148                         .PtrInBuf = .PtrInBuf + 1
149                         lEndLineSignLast = 2573 上次的分行符为 vbCrLf
150                     Else
151                         第1个字节不是 vbLf,而因为要忽略第1个 vbLf _
152                           说明上一行最后是 vbCr,故设置上一行分行符为 vbCr
153                         lEndLineSignLast = 13
154                     End If If .bufBytes(.PtrInBuf) = 10 Then
155                     
156                     .IgnoreFirstLf = False 恢复标志,不忽略第一个 vbLf
157                 End If If .IgnoreFirstLf Then
158                 
159                 初始化下一行起始位置 ptrNextStrStartInBuf (下一行内容包含该字节)
160                 .ptrNextStrStartInBuf = .PtrInBuf
161             End If If .PtrInBuf < 0 Then
162             
163             ============ (2)逐个扫描缓冲区中的字节,查找分行符 ============
164             扫描缓冲区中的字节,直到找到 vbCr或vbLf 或扫描完缓冲区
165             For .PtrInBuf = .PtrInBuf To .BufLen
166                 ch = .bufBytes(.PtrInBuf)
167                 Select Case State 34代表双引号 44代表逗号
168                     Case NewFieldStart
169                         If ch = 34 Then
170                             State = QuotesField
171                         ElseIf ch = 44 Then
172                             lineArr.Add ""
173                             State = FieldSeparator
174                         ElseIf ch = 13 Or ch = 10 Then
175                             State = NewFieldStart
176                             Exit For
177                         Else
178 
179                             strArrlBuff = strArrlBuff + 1
180                             If strArrlBuff Mod mcInitBuffSize = 0 Then
181                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
182                             End If
183                             ReDim Preserve strArr(1 To strArrlBuff)
184                             strArr(strArrlBuff) = ch
185                             strArr.Add ch
186                             State = NonQuotesField
187                         End If
188                     Case NonQuotesField
189                         If ch = 44 Then
190                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
191                             Erase strArr
192                             ReDim strArr(1 To mcInitBuffSize)
193                             strArrlBuff = 0
194                             Set strArr = New Collection
195                             State = FieldSeparator
196                         ElseIf ch = 13 Then
197                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
198                             State = RowSeparator
199                         Else
200                             strArrlBuff = strArrlBuff + 1
201                             If strArrlBuff Mod mcInitBuffSize = 0 Then
202                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
203                             End If
204                             ReDim Preserve strArr(1 To strArrlBuff)
205                             strArr(strArrlBuff) = ch
206                             strArr.Add ch
207                         End If
208                     Case QuotesField
209                         If ch = 34 Then
210                             State = QuoteInQuotesField
211                         Else
212                             strArrlBuff = strArrlBuff + 1
213                             If strArrlBuff Mod mcInitBuffSize = 0 Then
214                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
215                             End If
216                             ReDim Preserve strArr(1 To strArrlBuff)
217                             strArr(strArrlBuff) = ch
218                             strArr.Add ch
219                         End If
220                     Case FieldSeparator
221                         If ch = 44 Then
222                             lineArr.Add ""
223                         ElseIf ch = 34 Then
224                             Erase strArr
225                             ReDim strArr(1 To mcInitBuffSize)
226                             strArrlBuff = 0
227                             Set strArr = New Collection
228                             State = QuotesField
229                         ElseIf ch = 13 Then
230                             lineArr.Add ""
231                             State = RowSeparator
232                         Else
233                             strArrlBuff = strArrlBuff + 1
234                             If strArrlBuff Mod mcInitBuffSize = 0 Then
235                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
236                             End If
237                             ReDim Preserve strArr(1 To strArrlBuff)
238                             strArr(strArrlBuff) = ch
239                             strArr.Add ch
240                             State = NonQuotesField
241                         End If
242                     Case QuoteInQuotesField
243                         If ch = 44 Then
244                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
245                             Erase strArr
246                             ReDim strArr(1 To mcInitBuffSize)
247                             strArrlBuff = 0
248                             Set strArr = New Collection
249                             State = FieldSeparator
250                         ElseIf ch = 13 Then
251                             lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
252                             State = RowSeparator
253                         ElseIf ch = 34 Then
254                             strArrlBuff = strArrlBuff + 1
255                             If strArrlBuff Mod mcInitBuffSize = 0 Then
256                                 ReDim Preserve strArr(1 To strArrlBuff + mcInitBuffSize)
257                             End If
258                             ReDim Preserve strArr(1 To strArrlBuff)
259                             strArr(strArrlBuff) = ch
260                             strArr.Add ch
261                             State = QuotesField
262                         Else
263                             State = ErrorS "语法错误: 转义字符 \" 不能完成转义 或 引号字段结尾引号没有紧贴字段分隔符";
264                         End If
265                     Case RowSeparator
266                         If ch = 10 Then
267                             Erase strArr
268                             ReDim strArr(1 To mcInitBuffSize)
269                             strArrlBuff = 0
270                             Set strArr = New Collection
271                             State = NewFieldStart
272                             Exit For
273                         Else
274                             State = ErrorS "语法错误: 行分隔用了回车 \\r。但未使用回车换行 \\r\\n ";
275                         End If
276                     Case ErrorS
277                         GoTo errExit
278                                             
279                 End Select
280 
281                 If .bufBytes(.PtrInBuf) = 13 Or _
282                  .bufBytes(.PtrInBuf) = 10 Then Exit For
283             Next .PtrInBuf
284             
285             退出 For 后,判断是否找到了分行符 vbCr或vbLf
286             If .PtrInBuf <= .BufLen Then  是否找到了 vbCr或vbLf
287             
288                 ============ (3)找到一个分行符 vbCr或vbLf ============
289                 本行读到位置:af_Buff.PtrInBuf - 1
290                 
291                 ---- 设置本行换行符 ----
292                 lEndLineSign = .bufBytes(.PtrInBuf)
293                 
294                 ---- 生成要返回的本行字符串到:af_strBuf ----
295                 If .PtrInBuf - .ptrNextStrStartInBuf + af_LastBuff.LeftBLen < 1 Then
296                     .PtrInBuf = .ptrNextStrStartInBuf 时,例如 .PtrInBuf
297                       = .ptrNextStrStartInBuf=1 时,即开始就是 vbCr/vbLf
298                     af_strBuf = ""
299                 Else
300                     -- 将要返回的字符串的所有字节:包括上次剩余的 和 本次到 _
301                       .PtrInBuff 的(不算 .PtrInBuff 位置的)全部存入 af_bytsBuf() 数组 --
302                     ReDim af_bytsBuf(1 To .PtrInBuf - .ptrNextStrStartInBuf + af_LastBuff.LeftBLen)
303                     
304                     先保存上次剩余的字节 LeftBytes,存到 af_bytsBuf 的开始
305                     With af_LastBuff
306                         For j = 1 To .LeftBLen
307                             af_bytsBuf(j) = .LeftBytes(j)
308                         Next j
309                     End With
310                     
311                     再加上本次范围:[.ptrNextStrStartInBuf,.PtrInBuf) 的字节, _
312                       不包含 .PtrInBuf,因为 .PtrInBuf 是 vbCr/vbLf
313                     For j = 1 To .PtrInBuf - .ptrNextStrStartInBuf
314                         af_bytsBuf(j + af_LastBuff.LeftBLen) = _
315                           .bufBytes(.ptrNextStrStartInBuf + j - 1)
316                     Next j
317 
318                     -- 将 af_bytsBuf 中的字节转换为字符串到: af_strBuf --
319                     af_strBuf = af_bytsBuf
320 
321                     af_strBuf = EncodeStr(af_bytsBuf, EncodeErr) 代码转换
322                     If EncodeErr Then  代码转换出错
323                         GoTo errExit
324                     End If
325                     
326                     If lTrimSpaces Then af_strBuf = Trim(af_strBuf)
327                     
328                     -- 清除上次剩余的字节缓冲区 LeftBytes --
329                     Erase af_LastBuff.LeftBytes
330                     af_LastBuff.LeftBLen = 0
331                 End If
332                 
333                 ---- 判断是否是连续的 vbCr+vbLf,若是,跳过下一个 vbLf ----
334                 If .bufBytes(.PtrInBuf) = 13 Then
335                     If .PtrInBuf + 1 > .BufLen Then
336                         如果下一个字节已经超过这个缓冲区,则无法判断下一个字节 _
337                           是否是 vbLf,这里只设置标志,以后判断是否 vbLf 并决定跳过
338                         .IgnoreFirstLf = True
339                         lEndLineSign = -1
340                     Else
341                         下一个字节没超过这个缓冲区,下一个字节若是 vbLf 则直接跳过
342                         If .bufBytes(.PtrInBuf + 1) = 10 Then
343                             .PtrInBuf = .PtrInBuf + 1
344                             lEndLineSign = 2573
345                         End If
346                     End If
347                 End If
348                 
349                 ---- 设置当前缓冲区内部的下一行的起始位置 ----
350                 注:这里还未使 .PtrInBuf + 1
351                 .ptrNextStrStartInBuf = .PtrInBuf + 1 下一行字符包括这个字节
352                 
353                 ---- 返回:判断是否已经读完文件 ----
354                 .PtrInBuf 要 + 1 参与判断,因为本次循环后 .PtrInBuf 要 +1,现在还未 +1
355                 是否读完文件的标志存到 lIsEndRead,出 if 后据此决定返回值
356                 If .PtrInBuf + 1 > .BufLen And _
357                   .StartPosAbso + .BufLen > af_lngFileLength Then
358                     已经读完文件
359                     lIsEndRead = True
360                     If lAutoClose Then CloseFile
361                 Else
362                     还未读完文件,再判断是否文件只剩一个字节;若只剩一个字节并且 _
363                       剩下的正好是 vbLf,并且下次要忽略掉 vbLf,则仍是已经读完文件
364                     If .StartPosAbso + .BufLen = af_lngFileLength And .IgnoreFirstLf Then
365                         读取文件中的最后一个字节,只测试一下
366                         Dim tByt() As Byte, tRet As Integer
367                         tRet = FileGetBytesLocal(.StartPosAbso + .BufLen, tByt())
368                         If tRet <= 0 Then GoTo errExit 出错处理
369                         If tByt(1) = 10 Then
370                             已经读完文件
371                             lEndLineSign = 2573
372                             lIsEndRead = True
373                             If lAutoClose Then CloseFile
374                         End If
375                     End If
376                 End If
377                 .PtrInBuf = .PtrInBuf + 1
378                 
379                 找到了 vbCr/vbLf 返回这一行到:RetString,并退出函数 _
380                 但在退出前判断忽略空行,如果是空行就不退出而继续 Loop
381                 If lIsEndRead Then
382                     已经读完文件,一定 Exit Function
383                     RetString = af_strBuf
384                     Set col = lineArr
385                     Set lineArr = New Collection
386                     strArrlBuff = 0
387                     If lIgnoreEmpty And Len(af_strBuf) = 0 Then
388                         需要忽略空行,且最后一行为空行返回0,但不属于错误
389                         GetNextLine = 0
390                     Else
391                         不需要忽略空行或最后不是空行,但读完了文件,_
392                           不是返回1而是返回-1
393                         GetNextLine = -1
394                     End If
395                     Exit Function 已经读完文件,一定 Exit Function
396                 Else If lIsEndRead Then
397                     没有读完文件(忽略空行不退出,否则退出)
398                     If lIgnoreEmpty And Len(af_strBuf) = 0 Then
399                         忽略空行,不 Exit Function
400                         
401                     Else
402                         不需要忽略空行或最后不是空行,退出
403                         RetString = af_strBuf
404                         Set col = lineArr
405                         Set lineArr = New Collection
406                         strArrlBuff = 0
407                         GetNextLine = 1
408                         Exit Function
409                     End If
410                 End If If lIsEndRead Then
411                 
412             Else If .PtrInBuf <= .BufLen Then ‘是否找到了 vbCr或vbLf
413                 ============ (4)没有找到分行符“vbCr或vbLf”的处理 ============
414                 设置标志,=-1 表示下次要重新读取新的缓冲区, _
415                   否则不重新读取,仍使用当前缓冲区和 .PtrInBuf 指针
416                 .PtrInBuf = -1
417                 
418                 ==== 看缓冲区中是否还有剩余未处理的字节,若有, _
419                   将剩余的存入 af_LastBuff.LeftBytes() ====
420                 If .ptrNextStrStartInBuf <= .BufLen Then
421                     ReDim Preserve af_LastBuff.LeftBytes(1 To _
422                       .BufLen - .ptrNextStrStartInBuf + 1 + af_LastBuff.LeftBLen)
423                     For j = 1 To .BufLen - .ptrNextStrStartInBuf + 1
424                         af_LastBuff.LeftBytes(j + af_LastBuff.LeftBLen) _
425                           = .bufBytes(.ptrNextStrStartInBuf + j - 1)
426                     Next j
427                     af_LastBuff.LeftBLen = .BufLen - _
428                       .ptrNextStrStartInBuf + 1 + af_LastBuff.LeftBLen
429                 End If
430                 
431                 ==== 准备继续读下一个缓冲区 ====
432                 .StartPosAbso = .StartPosAbso + .BufLen
433             End If If .PtrInBuf <= .BufLen Then ‘是否找到了 vbCr或vbLf
434         Loop
435     End With
436     
437     
438     //////////// 全部读完文件,看还有无剩余的 ////////////
439     If af_LastBuff.LeftBLen > 0 Then
440         
441         Select Case State
442             Case NonQuotesField
443                  lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
444                  Erase strArr
445                  ReDim strArr(1 To mcInitBuffSize)
446                  strArrlBuff = 0
447                  lineArr.Add strArr
448                  Set strArr = New Collection
449             Case QuotesField
450                  GoTo errExit "语法错误: 引号字段未闭合";
451             Case FieldSeparator
452                 lineArr.Add ""
453             Case QuoteInQuotesField
454                 lineArr.Add EncodeStr(strArr, EncodeErr, strArrlBuff) 代码转换 strArr
455                 
456         End Select
457         
458         af_strBuf = af_LastBuff.LeftBytes
459         af_strBuf = EncodeStr(af_LastBuff.LeftBytes, EncodeErr)  代码转换
460         If EncodeErr Then 代码转换出错
461             GoTo errExit
462         End If
463         
464         af_strBuf = StrConv(af_strBuf, vbUnicode)
465         If lTrimSpaces Then af_strBuf = Trim(af_strBuf)
466         RetString = af_strBuf
467         Set col = lineArr
468         Set lineArr = New Collection
469         strArrlBuff = 0
470         
471         Erase af_LastBuff.LeftBytes
472         af_LastBuff.LeftBLen = 0
473         If lIgnoreEmpty And Len(af_strBuf) = 0 Then
474             GetNextLine = 0
475         Else
476             GetNextLine = -1
477         End If
478         
479         If lAutoClose Then CloseFile
480         lEndLineSign = -2
481         lIsEndRead = True
482         此时读完文件,必须返回
483         Exit Function
484     End If
485     
486 
487 errExit:
488     lErrOccured = True
489     lEndLineSign = 0
490     GetNextLine = 0
491     为一般错误,不设置 lIsEndRead = True
492     If lAutoClose Then CloseFile
493 End Function
494 
495 Private Function EncodeStr(ByRef bytIn() As Byte, hasError As Boolean, Optional byteSize As Long = -1) As String
496 
497     Select Case Encode
498         Case Default
499             Dim tempStr As String
500             tempStr = bytIn
501             EncodeStr = StrConv(tempStr, vbUnicode)
502 
503         Case ShifJis
504             EncodeStr = WCMB_Decode(ShifJis, bytIn, hasError, byteSize)
505         Case JIS
506              EncodeStr = WCMB_Decode(JIS, bytIn, hasError, byteSize)
507         Case Utf8
508             EncodeStr = WCMB_Decode(Utf8, bytIn, hasError, byteSize)
509         Case GB2312
510              EncodeStr = WCMB_Decode(GB2312, bytIn, hasError, byteSize)
511     End Select
512 
513 End Function
514 
515 
516  関数名    : WCMB_Decode
517  返り値    : UNICODE文字列
518  引き数    : cp    : 入力文字データのコードページ番号
519            : bytIn : 入力文字データ
520  機能説明  : 入力文字データをUNICODEに変換する
521  備考      : MultiByteToWideCharによる文字コード変換
522 Private Function WCMB_Decode(ByVal cp As Long, ByRef bytIn() As Byte, ByRef hasError As Boolean, Optional byteSize As Long = -1) As String
523     On Error GoTo ErrHandler
524 
525     Dim lngInSize As Long
526     Dim strBuf As String
527     Dim lngBufLen As Long
528     Dim lngRtn As Long
529     If byteSize > 0 Then
530         lngInSize = byteSize
531     Else
532         If bytIn(UBound(bytIn)) = 13 Then
533             lngInSize = UBound(bytIn) - 1
534         Else
535             lngInSize = UBound(bytIn)
536         End If
537     End If
538     lngBufLen = (lngInSize + 1) * 5
539     strBuf = String$(lngBufLen, vbNullChar)
540     lngRtn = MultiByteToWideChar _
541         (cp, 0, bytIn(1), lngInSize, StrPtr(strBuf), lngBufLen)
542     If lngRtn Then
543         WCMB_Decode = Left$(strBuf, lngRtn)
544     End If
545     hasError = False
546     Exit Function
547 ErrHandler:
548     WCMB_Decode = ""
549     hasError = True
550 End Function
551 
552 Public Sub Init()
553 
554     ReDim strArr(1 To mcInitBuffSize) CSV 各个单元 缓冲区
555     strArrlBuff = 0
556                  
557     Erase af_Buff.bufBytes 缓冲区
558     
559     Erase af_LastBuff.LeftBytes
560     af_LastBuff.LeftBLen = 0
561     
562     af_strBuf = ""
563     af_lngFileLength = 0
564     af_Buff.StartPosAbso = 1 当前缓冲区的起始处所在的文件位置
565     af_Buff.ptrNextStrStartInBuf = 1
566     
567     此作为标志,=-1表示下次运行 GetNextLine 要重新读取新的缓冲区 _
568       否则不重新读取,仍使用当前缓冲区和 .PtrInBuf 指针
569     af_Buff.PtrInBuf = -1
570     
571     af_OneEndRead = True 设置标志:关闭后再调用一次 GetNextLine 不出错
572     lErrOccured = False
573     lEndLineSign = 0
574     lEndLineSignLast = 0
575     
576     af_Buff.IgnoreFirstLf = False 初始化标志:当前缓冲区不需要忽略第一个字节(若是vblf)
577     
578     lIsEndRead = False
579 End Sub
580 
581 Public Function GetPercent(Optional DotNum As Integer = 2) As Single
582     DotNum保留几位小数,<0或>7为不保留小数
583     Dim sngPerc As Single
584     
585     If af_lngFileLength > 0 Then
586         If af_Buff.PtrInBuf < 0 Then
587             sngPerc = (af_Buff.StartPosAbso - 1) / af_lngFileLength
588         Else
589             sngPerc = (af_Buff.StartPosAbso + af_Buff.PtrInBuf - 2) / af_lngFileLength
590         End If
591     End If
592     
593     If DotNum >= 0 Or DotNum <= 7 Then
594         Dim Temp As Long
595         Temp = 10 ^ DotNum
596         sngPerc = Int(Temp * sngPerc + 0.5) / Temp
597     End If
598     
599     GetPercent = sngPerc
600 End Function
601 
602 Public Sub CloseFile()
603     If lFileNum > 0 Then Close lFileNum: lFileNum = 0
604     lStatus = -1 表示文件已关闭
605     不Init,防止读取行后自动关闭文件时状态变量被初始化;在OpenFile时会Init
606 End Sub
607 
608 Public Function OpenFile() As Boolean
609     If lFileNum > 0 Then CloseFile 如果已打开了文件,则先关闭它
610     lFileNum = FreeFile 获得一个可用的文件号(同时属性 FileNum 的值也自动改变)
611     On Error GoTo errH 如果一下程序发生任何错误,就转到 errH 标签处执行
612     If Dir(lFileName, 31) = "" Then GoTo errH 如果文件不存在,就转到 errH 标签处执行
613     Open lFileName For Binary Access Read As #lFileNum 以二进制方式打开文件
614     lStatus = 1 表示文件已打开
615     Init 初始化操作
616     af_lngFileLength = LOF(lFileNum) 设置文件总大小
617     OpenFile = True
618     Exit Function
619 errH:
620     If lFileNum > 0 Then CloseFile
621     OpenFile = False
622 End Function
623 
624 
625 
626 Private Function FileGetBytesLocal(ByVal ReadPos As Long, _
627                                          ArrBytes() As Byte, _
628                           Optional ByVal EndingBorder As Long = 0, _
629                           Optional ByVal ReadMax As Long = 16384) As Long
630                           Optional ByVal ReadMax As Long = 16384, _
631     从文件号 lFileNum 中的 ReadPos 位置开始读取一批字节
632     从参数ArrBytes()返回读取的字节内容,会重新定义ArrBytes()数组
633     所读取的字节数不确定,如果文件中有足够的内容,就读取ReadMax个字节, _
634       否则就读到文件尾(当EndingBorder参数<=0时)或读到EndingBorder _
635       为止(当EndingBorder参数>0时)
636     ShowResume 指定如果读取出错,是否弹出对话框提示
637       若ShowResume=1,提示框中有"重试"和"取消"两个按钮;
638       若ShowResume=2,出错时提示框中有"终止"、"重试"和"忽略"三个按钮;
639       若ShowResume=0,出错时不弹出提示框,不弹出提示框就不能在发生错误时重试
640     返回读取的字节数,若失败返回<=0,若用户“忽略”则返回=0;_
641       若用户终止或取消或无提示框,则返回<0
642     
643     Dim lngUBound As Long
644     
645     If EndingBorder <= 0 Then EndingBorder = LOF(lFileNum)
646     If EndingBorder < ReadPos Then
647         FileGetBytesLocal = -1
648         Exit Function
649     End If
650     
651     On Error GoTo errH
652     If EndingBorder - ReadPos + 1 >= ReadMax Then lngUBound = ReadMax Else _
653       lngUBound = EndingBorder - ReadPos + 1
654     
655     ReDim ArrBytes(1 To lngUBound) As Byte
656     
657     Get #FileNum, ReadPos, ArrBytes
658 
659     FileGetBytesLocal = lngUBound
660     Exit Function
661 errH:
662      FileGetBytesLocal = -1
663 End Function
664 
665 
666 
667 Private Sub Class_Initialize()
668     lAutoOpen = True 设置 FileName 属性时自动打开文件
669     lAutoClose = True 读取行读完文件或出错时 自动关闭文件
670     lTrimSpaces = False 不自动Trim()结果行
671     lIgnoreEmpty = True 是否自动忽略空行(注意:如果是最后一行仍可能返回空行)
672 End Sub
673 
674 Private Sub Class_Terminate()
675     CloseFile
676     Erase af_Buff.bufBytes
677     Erase af_LastBuff.LeftBytes
678     Erase af_bytsBuf
679 End Sub
680 
681 
682 Public Property Get FileName() As String
683     FileName = lFileName
684 End Property
685 
686 Public Property Let FileName(ByVal vNewValue As String)
687     If lFileNum > 0 Then CloseFile
688     lFileName = vNewValue
689     If lAutoOpen Then OpenFile
690 End Property
691 
692 Public Property Get FileNum() As Integer
693     FileNum = lFileNum
694 End Property
695 
696 Public Property Get Status() As Integer
697     Status = lStatus
698 End Property
699 
700 Public Property Get IsEndRead() As Boolean
701     IsEndRead = lIsEndRead
702 End Property
703 
704 
705 Public Property Get TrimSpaces() As Boolean
706     TrimSpaces = lTrimSpaces
707 End Property
708 
709 Public Property Let TrimSpaces(ByVal vNewValue As Boolean)
710     lTrimSpaces = vNewValue
711 End Property
712 
713 Public Property Get AutoOpen() As Boolean
714     AutoOpen = lAutoOpen
715 End Property
716 
717 Public Property Let AutoOpen(ByVal vNewValue As Boolean)
718     lAutoOpen = vNewValue
719 End Property
720 
721 Public Property Get AutoClose() As Boolean
722     AutoClose = lAutoClose
723 End Property
724 
725 Public Property Let AutoClose(ByVal vNewValue As Boolean)
726     lAutoClose = vNewValue
727 End Property
728 
729 Public Property Get IgnoreEmpty() As Boolean 是否自动忽略空行 ""
730     IgnoreEmpty = lIgnoreEmpty
731 End Property
732 
733 Public Property Let IgnoreEmpty(ByVal vNewValue As Boolean)
734     lIgnoreEmpty = vNewValue
735 End Property
736 
737 Public Property Get EndLineSign() As Integer
738     EndLineSign = lEndLineSign
739 End Property
740 
741 Public Property Get EndLineSignLast() As Integer
742     EndLineSignLast = lEndLineSignLast
743 End Property
744 
745 Public Property Get ErrOccured() As Boolean
746     ErrOccured = lErrOccured
747 End Property
748 
749 Public Property Let ErrOccured(ByVal vNewValue As Boolean)
750     lErrOccured = vNewValue
751 End Property
752 
753 Public Property Get Encode() As EncodeEnum
754     Encode = lEncode
755 End Property
756 
757 Public Property Let Encode(ByVal vNewValue As EncodeEnum)
758     lEncode = vNewValue
759 End Property
760 
761 Public Property Get IsEncodeErr() As Boolean
762     IsEncodeErr = EncodeErr
763 End Property
分别解析Item 和 整行内容

 

 1 Dim aFile As clsCsv
 2 
 3 Dim strCol As Collection
 4 
 5 Set aFile = New clsCsv
 6 
 7 aFile.FileName = "C:\Users\Administrator\Desktop\Àϱøд«³ÌÐòÔ´´úÂë\µÚ6ÕÂ\Îı¾Îļþ°´ÐжÁÈ¡\ʾÀýÎļþ(»»Ðзû·ÖÐÐ).csv"
 8 
 9 aFile.Encode = Utf8
10 
11 Do Until aFile.IsEndRead
12         aFile.GetNextLine strCol
13         If aFile.ErrOccured Then
14             Exit Do
15         Else
16            i = i + 1
17             Debug.Print strLine
18             Label1.Caption = aFile.GetPercent * 100 & "%"
19             If i Mod 500 = 1 Then DoEvents
20         End If
21     Loop

 

 

VBA CSV格式的解析类 【c语言CSV Parser转换】

标签:

原文地址:http://www.cnblogs.com/yuzhengdong/p/4217609.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!