Làm thế nào để tăng tốc độ đọc File txt (>100Mb) bị Encoding

Liên hệ QC MyVTV Add-ins

ganbarou

Thành viên mới
Tham gia ngày
18 Tháng năm 2021
Bài viết
25
Được thích
3
Giới tính
Nam
Chào mọi người. Hiện tại em đang mắc tại bài toán như sau:
Bài toán: Đọc và kiểm tra từng dòng trong file txt. Các file txt lớn hơn 100Mb và bị Encoding EUC-JP.
Code hiện tại của em như thế này:

Mã:
Sub test()
    Dim ObjStream As Object
    Dim strTmp As String
    Dim filepath As String

   filepath = .......... 'duong dan file

    Set ObjStream = CreateObject("ADODB.stream")
    With ObjStream
        .Type = adTypeText
        .Charset = "EUC-JP"
        .LineSeparator = adLF
        .Open
        Call .LoadFromFile(filepath)
    End With
  
    Do Until ObjStream.EOS
        strTmp = ObjStream.ReadText(adReadLine)
        Debug.Print strTmp
    Loop

    ObjStream.Close
    Set ObjStream = Nothing
End Sub

Vấn đề: Với code trên thì thời gian để đọc toàn bộ file 100Mb là khoảng 2 phút. Em muốn rút ngắn thời gian này lại thì nên làm như thế nào ạ?

Update: Em trình bày thêm một tý yêu cầu:
Hình bên dưới là một phần bé tý trong cái file em cần lấy dữ liệu. Mấy cái khung màu đỏ là thông tin muốn lấy (mỗi lần lấy bất kỳ 1 cái nào trong đống đấy)
Em làm được phần này sơ sơ rồi, nhưng phải đọc từng dòng 1 trong file như code trên (thay dòng debug.print bằng đoạn khác để xử lý). Nhưng cách này khá mất thời gian nên em lên đây mong mọi người giúp đỡ, tìm kiếm giải pháp tốt hơn.

ab.png

!!! Do vấn đề bảo mật nên hiện tại em không thể đăng tải file demo lên, em sẽ tìm cách đăng sau!!!
Mọi giải pháp đưa ra đều rất quý giá với em, mong mọi người giúp đỡ.
!!!Lần đầu em động đến cái VBA, với mới tham gia diễn đàn nên nhiều cái ngu lắm mong mọi người bỏ qua ^^
 
Lần chỉnh sửa cuối:

befaint

|||||||||||||
Tham gia ngày
6 Tháng một 2011
Bài viết
11,647
Được thích
14,050
Đề mo thì viết oằn tà là vằn vào đó thì bí mật với bí đường làm sao, hoặc chụp hình xinh xinh cũng được.

Đọc phát cả file luôn, ai kêu đọc từng dòng làm gì cho mệt.

Cái quan trọng lấy dữ liệu trong file đó làm gì ấy, mình nêu cái mong muốn cuối cùng á.
 

VetMini

Chuyên gia GPE
Tham gia ngày
21 Tháng mười hai 2012
Bài viết
11,741
Được thích
14,865
...Vấn đề: Với code trên thì thời gian để đọc toàn bộ file 100Mb là khoảng 2 phút. Em muốn rút ngắn thời gian này lại thì nên làm như thế nào ạ?
Bỏ cái dòng Debug.Print đi. Ít nhất cũng nhanh được một chút.

Đề mo thì viết oằn tà là vằn vào đó thì bí mật với bí đường làm sao, hoặc chụp hình xinh xinh cũng được.
...
oằn cái khỉ mốc. Code này là code spider, lần file để tìm chỗ quan trọng mà trích ra.

...
Đọc phát cả file luôn, ai kêu đọc từng dòng làm gì cho mệt.

Cái quan trọng lấy dữ liệu trong file đó làm gì ấy, mình nêu cái mong muốn cuối cùng á.
1. Code spider đọc cả file mệt lắm. Nếu mỗi dòng liên quan đến một mảng tài liệu thì phân ra càng thêm mệt.

2. Làm gì? Dụ người ta vào quép sai của mình rồi gom thông tin cá nhơn về nghiêng cú thì có dám khai với bạn không?

Chuyện phiếm: hình như hiện tại có mụ đại da nạ dòng nào đó tuyên bố sẵn sàng bỏ ra hằng ngàn tỷ để mướn hắc-cờ lấy thông tin những người chống đối mình. Chuyến này anh em hắc-cơ tha hồ hưởng lợi.
Chỉ nghiệp dân ta, chưa dứt khổ với nạn quan quyền còn phải chịu bọn đại da chúng đè đầu hăm doạ đủ thứ.
 

ganbarou

Thành viên mới
Tham gia ngày
18 Tháng năm 2021
Bài viết
25
Được thích
3
Giới tính
Nam
Đề mo thì viết oằn tà là vằn vào đó thì bí mật với bí đường làm sao, hoặc chụp hình xinh xinh cũng được.

Đọc phát cả file luôn, ai kêu đọc từng dòng làm gì cho mệt.

Cái quan trọng lấy dữ liệu trong file đó làm gì ấy, mình nêu cái mong muốn cuối cùng á.
em chưa thử đọc một phát cả file, để em tìm hiểu cách làm xem sao.

Mục đích thì là trích một hoặc nhiều dữ liệu bất kỳ ra rồi ghi vào file excel.

!!!Lần đầu em động đến cái VBA, với mới tham gia diễn đàn nên nhiều cái ngu lắm mong mọi người bỏ qua ^^
Bài đã được tự động gộp:

Bỏ cái dòng Debug.Print đi. Ít nhất cũng nhanh được một chút.
Cái đấy em cho vào cho có thôi, chứ em làm việc khác ở đấy
1. Code spider đọc cả file mệt lắm. Nếu mỗi dòng liên quan đến một mảng tài liệu thì phân ra càng thêm mệt.
Cho em hỏi ngu phát là code Spider là gì vậy ạ?

Cái file cua em thì là file log event của một cái máy. Mỗi dòng nó ghi thông tin khác nhau, có thông tin thì nó ghi thành nhiều dòng. Nên lúc đầu làm em chỉ nghĩ đến việc đọc từng dòng 1 rồi phân tích nó để lấy dữ liệu, chứ không thử cách khác ^^
 
Lần chỉnh sửa cuối:

befaint

|||||||||||||
Tham gia ngày
6 Tháng một 2011
Bài viết
11,647
Được thích
14,050
em chưa thử đọc một phát cả file, để em tìm hiểu cách làm xem sao.

Mục đích thì là trích một hoặc nhiều dữ liệu bất kỳ ra rồi ghi vào file excel.

!!!Lần đầu em động đến cái VBA, với mới tham gia diễn đàn nên nhiều cái ngu lắm mong mọi người bỏ qua ^^
Đâu cứ phải Excel, đâu cứ phải VBA làm gì. Đang biết lập trình theo cách nào thì cứ cái đó làm đi.

Túm lại, cứ nêu bài toán cụ thể, chi tiết của mình. Còn nêu ý tưởng kiểu này rồi lùa đám lừa chạy theo mệt lắm.
 

ganbarou

Thành viên mới
Tham gia ngày
18 Tháng năm 2021
Bài viết
25
Được thích
3
Giới tính
Nam
Đâu cứ phải Excel, đâu cứ phải VBA làm gì. Đang biết lập trình theo cách nào thì cứ cái đó làm đi.

Túm lại, cứ nêu bài toán cụ thể, chi tiết của mình. Còn nêu ý tưởng kiểu này rồi lùa đám lừa chạy theo mệt lắm.
em có muốn dung vba đâu, sếp kêu làm bằng vba để người khác còn dùng nữa :(
em update trên bài viết rồi, anh xem qua, không hợp ý nào thì nhắc e để em sửa với ^^
 

befaint

|||||||||||||
Tham gia ngày
6 Tháng một 2011
Bài viết
11,647
Được thích
14,050
em có muốn dung vba đâu, sếp kêu làm bằng vba để người khác còn dùng nữa :(
em update trên bài viết rồi, anh xem qua, không hợp ý nào thì nhắc e để em sửa với ^^
Bạn thử tạm cách này xem:

Đọc hết cả file luôn, được 1 chuỗi. Dùng split bẻ chuỗi này bằng dấu phân cách ngắt dòng (chr(10), chr(13), vbcrlf, vbnewline... gì đó), được 1 mảng (array) với mỗi phần từ là 1 dòng. Rồi tới phần của bạn đã làm, duyệt từng phần tử của mảng đó là được.
 

VetMini

Chuyên gia GPE
Tham gia ngày
21 Tháng mười hai 2012
Bài viết
11,741
Được thích
14,865
em có muốn dung vba đâu, sếp kêu làm bằng vba để người khác còn dùng nữa :(
em update trên bài viết rồi, anh xem qua, không hợp ý nào thì nhắc e để em sửa với ^^
Lại gặp tay đổ thừa sếp ngu. Muốn VBA thì phải có Office, "người khác còn dùng" cía mốc gì? Nếu ai cũng dùng đơcj thì phải là VBS chứ.
Theo quan điểm "chơi hàng xịn" thì cái này làm đúng điệu nhất là dùng đồ của PERL, điển hình là GREP, lấy dữ liệu ra CSV.

update: bạn muốn người ta hiểu chỗ này theo ngữ pháp (không phải ngữ cảnh) tiếng Việt hay tiếng Anh?
 

ganbarou

Thành viên mới
Tham gia ngày
18 Tháng năm 2021
Bài viết
25
Được thích
3
Giới tính
Nam
Bạn thử tạm cách này xem:

Đọc hết cả file luôn, được 1 chuỗi. Dùng split bẻ chuỗi này bằng dấu phân cách ngắt dòng (chr(10), chr(13), vbcrlf, vbnewline... gì đó), được 1 mảng (array) với mỗi phần từ là 1 dòng. Rồi tới phần của bạn đã làm, duyệt từng phần tử của mảng đó là được.
Mã:
Sub test()
    Dim ObjStream As Object
    Dim strTmp As String
    Dim filepath As String

   filepath = .......... 'duong dan file

    Set ObjStream = CreateObject("ADODB.stream")
    With ObjStream
        .Charset = "EUC-JP"
        .Open
        Call .LoadFromFile(filepath)
    End With
    strTmp = ObjStream.ReadText(adReadAll)

   ObjStream.Close
    Set ObjStream = Nothing
End Sub

Cho em hỏi, tại sao em đọc toàn bộ file bằng code trên thì không đọc được nhỉ. A dùng cách nào để đọc vậy ạ?
Bài đã được tự động gộp:

Lại gặp tay đổ thừa sếp ngu. Muốn VBA thì phải có Office, "người khác còn dùng" cía mốc gì? Nếu ai cũng dùng đơcj thì phải là VBS chứ.
Theo quan điểm "chơi hàng xịn" thì cái này làm đúng điệu nhất là dùng đồ của PERL, điển hình là GREP, lấy dữ liệu ra CSV.

update: bạn muốn người ta hiểu chỗ này theo ngữ pháp (không phải ngữ cảnh) tiếng Việt hay tiếng Anh?
cài này có lẽ do cách dùng từ của em sai ^^
Tóm lại bài toán của em yêu cầu sử dụng excel và VBA, còn về PERL hay GREP thì em chưa biết là gì.
 

ganbarou

Thành viên mới
Tham gia ngày
18 Tháng năm 2021
Bài viết
25
Được thích
3
Giới tính
Nam
đâu khác code bên trên em viết là mấy đâu ạ. có lỗi xuất hiện khi e tắt, mà nhanh qua chưa kịp nhìn, đợi chụp được em gửi lên cho a xem sau
Bài đã được tự động gộp:

Sao biết không đọc được? Thêm Debug.Print strTmp vào thì mới nhìn thấy có đọc được hay không.
cái này em lỡ xóa mất rồi ^^, cùng 1 file bình thường em đọc từng dòng 1 thì mất gần 2 phút, còn em dùng code trên đợi lâu quá không có phản hồi gì.
 

befaint

|||||||||||||
Tham gia ngày
6 Tháng một 2011
Bài viết
11,647
Được thích
14,050

ganbarou

Thành viên mới
Tham gia ngày
18 Tháng năm 2021
Bài viết
25
Được thích
3
Giới tính
Nam
Sai ở dòng này này:
ObjStream.ReadText(adReadAll)

Khai báo muộn kiểu CreateObject thì phải dùng Value, dùng Constant là tèo.

View attachment 260327
để mai em thử, giờ em tan làm rồi
Bài đã được tự động gộp:

strTmp = ObjStream.ReadText(adReadLine)
tiện em hỏi,tại sao em dùng dòng này thì không có lỗi :))
 

batman1

Thành viên gạo cội
Tham gia ngày
8 Tháng chín 2014
Bài viết
4,250
Được thích
6,767
strTmp = ObjStream.ReadText(adReadLine)
tiện em hỏi,tại sao em dùng dòng này thì không có lỗi :))
KHÔNG THỂ CÓ LỖI ĐƯỢC ...

Bình thường thì VBA không thể biết adReadLine hay adReadLine là cái gì, vì chúng là các hằng số trong thư viện Microsoft ActiveX Data Objects.

Tôi xét code ở bài #1.

Nếu bạn không thêm reference Microsoft ActiveX Data Objects thì có 2 trường hợp:
1. Nếu có Option Explicit ở đầu module thì VBA sẽ báo lỗi không khai báo biến.

2. Nếu không có Option Explicit ở đầu module thì VBA coi adReadLine trong code ở bài #1 là biến không được khai báo tường minh, và ở thời điểm "chào buổi sáng" addReadLine = 0. Lúc này dòng strTmp = ObjStream.ReadText(adReadLine) sẽ gây ra lỗi.

Do code bài #1 chạy mượt, không có báo lỗi nên chỉ có thể là bạn có thêm reference Microsoft ActiveX Data Objects.

Khó sảy ra khả năng là ở bài #1 bạn thêm reference Microsoft ActiveX Data Objects nhưng ở bài #9 bạn lại bỏ reference Microsoft ActiveX Data Objects. Vậy tôi cho là ở bài #9 cũng có reference Microsoft ActiveX Data Objects. Khi đó thì không thể có lỗi ở dòng
strTmp = ObjStream.ReadText(adReadAll) được. Lỗi KHÔNG CÓ QUYỀN sảy ra ở dòng này.

Nếu bạn không thêm reference Microsoft ActiveX Data Objects thì bạn có thể khai báo các hằng số
Mã:
Const adReadLine = -2
Const adTypeText = 2
Const adLF = 10

và dùng các hằng số này trong code.

Hoặc chả khai báo hằng số gì cả mà nhập luôn vào code

Bài #1
...
.Type = 2
...
.LineSeparator = 10
...
strTmp = ObjStream.ReadText(-2)

Bài #9
strTmp = ObjStream.ReadText(-1) ' -1 thay cho adReadAll

Không có chuyện lỗi gì ở đây.
 

befaint

|||||||||||||
Tham gia ngày
6 Tháng một 2011
Bài viết
11,647
Được thích
14,050
Chưa bao giờ viết dòng đấy ^^
Vậy từ giờ thêm vào đi. Tụi jp làm việc nguyên tắc lắm cơ mà, cái gì cũng rất chặt chẽ á. Cái gì để chung nhiều người dùng thì phải đơn giản nhất, gọn gàng nhất, dễ dùng nhất, không có chuyện thêm nếm gì cả.
Khai báo biến rõ ràng thì đảm bảo chính xác, biến mà không khai báo tường minh thì nó rơi vào cái thể loại variant á, mà giá trị mặc định của nó là empty, empty, empty ấy. Là hổng có gì trong nó á.
 

batman1

Thành viên gạo cội
Tham gia ngày
8 Tháng chín 2014
Bài viết
4,250
Được thích
6,767
Empty tùy từng trường hợp cụ thể mà VBA ép về: Empty (tham số là Variant), hoặc 0 (tham số là numeric), chuỗi rỗng (tham số là String), False (tham số là Boolean), Nothing (tham số là Object). Không có chuyện luôn luôn là Empty.

Do trong bài #1 bạn không kêu ca có lỗi gì nên trong bài #17 tôi đoán là không thể có trường hợp 1 và 2. Vậy đoán mò là bạn có reference Microsoft ActiveX Data Objects. Và cái đoán mò đó tôi cho là cũng trong bài #9.

Tất nhiên nếu không có reference reference Microsoft ActiveX Data Objects và cả Option Explicit thì dĩ nhiên là có lỗi rồi. Không ai phủ nhận điều này.

Nếu code bài #9 không có reference và cả Option Explicit thì
adReadAll = Empty = 0 (VBA tự ép thôi)

Không đọc được gì thì dễ hiểu vì muốn đọc thì phải truyền -1 (đọc hết) hoặc -2 (đọc 1 dòng). Truyền 0 thì tham số không đúng nên không đọc được gì cả. Thế thôi.

Nên nhớ là với code ở bài #9 thì KHÔNG ĐỌC ĐƯỢC GÌ chứ không có LỖI, vd. Run-time error. Đây là 2 vấn đề khác nhau.

Như tôi đã viết ở bài #17, cứ khai báo thêm
Mã:
Const adReadAll = -1

hoặc sửa thành
Mã:
strTmp = ObjStream.ReadText(-1)

Thế thôi.

Cả 2 đoạn sửa trên là đủ, không cần có Option Explicit (bài #9). Nhưng có Option Explicit là THÓI QUEN TỐT, ai cũng công nhận, ai cũng ủng hộ.
 

ganbarou

Thành viên mới
Tham gia ngày
18 Tháng năm 2021
Bài viết
25
Được thích
3
Giới tính
Nam
Cảm ơn hai anh vẫn giúp đỡ trong khi em ngủ :v
Do code bài #1 chạy mượt, không có báo lỗi nên chỉ có thể là bạn có thêm reference Microsoft ActiveX Data Objects.
Mấy đoạn code trên em đều thêm Microsoft ActiveX Data Objects
Mã:
Sub test123()
    Dim ObjStream As Object
    Dim strTmp As String
    Dim path As String
    
    path = "C:\Users\toan_pham\Desktop\test\1\PEC_20210518.log"
    
    Set ObjStream = CreateObject("ADODB.stream")
    With ObjStream
        .Type = 2
        .Charset = "EUC-JP"
        .Open
        .LoadFromFile path
        Debug.Print "bat dau doc"
        strTmp = .ReadText(-1)
        Debug.Print "doc xong"
        .Close
    End With
 
    Set ObjStream = Nothing
    
    ThisWorkbook.Worksheets(3).Cells(1, 1) = left(strTmp, 23)

End Sub
Nay em có thử lại với đoạn code này:
File em đang thử test có dung lượng tầm 85MB. Bình thường em dùng code bài #1 sẽ mất tầm 2 phút, nhưng với code ở bài này em đợi hơn 3 phút không thấy phản hồi nên ép tắt chương trình và thấy báo lỗi sau:
asdasd.PNG
thông tin lỗi là không đủ bộ nhớ nên không thể thực thi. Với cấu hình máy em đang xài khó mà xảy ra tình trạng thiếu bộ nhớ được.
Hiện tại em chưa biết nguyên nhân do đâu, mong 2 anh giúp đỡ
 
Top Bottom