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

  • Thread starter Thread starter ganbarou
  • Ngày gửi Ngày gửi
Liên hệ QC

Người dùng đang xem chủ đề này

ganbarou

Thành viên mới
Tham gia
18/5/21
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:
Đề 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 á.
 
...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ứ.
 
Đề 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:
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.
 
Đâ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 ^^
 
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.
 
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?
 
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ì.
 
đâ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ì.
 
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.
 
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ó á.
 
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ộ.
 
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 đỡ
 
Cảm ơn hai anh vẫn giúp đỡ trong khi em ngủ :v

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:
Chưa chắc đọc 1 lần toàn bộ tập tin 100 MB nhanh hơn đọc từng dòng. Nếu dùng code ở bài #1 mất ít thời gian hơn thì sao lại cố dùng code ở trên?
 
Chưa chắc đọc 1 lần toàn bộ tập tin 100 MB nhanh hơn đọc từng dòng. Nếu dùng code ở bài #1 mất ít thời gian hơn thì sao lại cố dùng code ở trên?
Em đang xem cách đọc toàn bộ tập tin thì mất bao nhiêu thời gian, nếu ngắn hơn cách bài #1 thì em mới dùng.
Mục tiêu của em bây giờ là tìm xem có cách nào rút ngắn đựoc thời gian chạy chuơng trình hay không? Anh có ý tưởng nào có thể gợi ý cho em không ạ!
 
nói chung nếu xử lý tuần tự thì máy tính trâu bò mấy cũng đua ko lại với 100M dữ liệu trong 1 giây đâu !@@
mình phải thiết kế sao đó cho nó xử lý song song ấy ,
ví dụ có 10 chương trình chạy song song , chia nhau mỗi cái xử lý 10M chẳng hạn !
 
Em đang xem cách đọc toàn bộ tập tin thì mất bao nhiêu thời gian, nếu ngắn hơn cách bài #1 thì em mới dùng.
Mục tiêu của em bây giờ là tìm xem có cách nào rút ngắn đựoc thời gian chạy chuơng trình hay không? Anh có ý tưởng nào có thể gợi ý cho em không ạ!
Tối ưu thì người ta tối ưu cả chương trình, chứ đâu làm mỗi khúc nào đó.
Tất nhiên mọi khúc đều ngon thì cả chương trình đều ngon, nhưng đâu phải lúc nào cũng như mơ được vậy.
Ví dụ chương trình của bạn có 2 phần: Đọc dữ liệu từ tập tin, xử lý lấy dữ liệu.
Với cách đọc từng dòng giả sử hết t11=4 (thời gian), xử lý t12 = 6 (thời gian)
Với cách đọc cả tập tin một lúc giả sử hết t21 = 6 (thời gian), phần xử lý (dựa trên phần 1) t22 = 3 (thời gian).
Đó, rắc rối vậy á.
 
nói chung nếu xử lý tuần tự thì máy tính trâu bò mấy cũng đua ko lại với 100M dữ liệu trong 1 giây đâu !@@
mình phải thiết kế sao đó cho nó xử lý song song ấy ,
ví dụ có 10 chương trình chạy song song , chia nhau mỗi cái xử lý 10M chẳng hạn !
Nếu đúng file Text, thì chia nhỏ ra nhiều File
Thì đọc từng File sẽ nhanh, và tìm ra Kết quả thì dừng
 
suy luận của bạn đã có vẻ tiến hóa hơn chút , nhưng về giải pháp thì chương trình vẫn gánh 100M theo kiểu tuần tự !@@
 
suy luận của bạn đã có vẻ tiến hóa hơn chút , nhưng về giải pháp thì chương trình vẫn gánh 100M theo kiểu tuần tự !@@
Có thể, vì chưa biết người hỏi chạy code gì tìm cái gì, nên đó chỉ là 1 giải pháp tham khảo
@người hỏi: Cần rõ là tìm gì, và kiểm soát gì, cấu trúc file đó là gì?
 
Thông tin em cần lấy có thể ở bất kỳ chỗ nào trong file nên bắt buộc phải đọc hết file mới biết là hết thông tin hay chưa.
nói chung nếu xử lý tuần tự thì máy tính trâu bò mấy cũng đua ko lại với 100M dữ liệu trong 1 giây đâu !@@
mình phải thiết kế sao đó cho nó xử lý song song ấy ,
ví dụ có 10 chương trình chạy song song , chia nhau mỗi cái xử lý 10M chẳng hạn !
làm thế nào để xử lý song song với VBA ạ, cái này em không biết!

Tối ưu thì người ta tối ưu cả chương trình, chứ đâu làm mỗi khúc nào đó.
Tất nhiên mọi khúc đều ngon thì cả chương trình đều ngon, nhưng đâu phải lúc nào cũng như mơ được vậy.
Ví dụ chương trình của bạn có 2 phần: Đọc dữ liệu từ tập tin, xử lý lấy dữ liệu.
Với cách đọc từng dòng giả sử hết t11=4 (thời gian), xử lý t12 = 6 (thời gian)
Với cách đọc cả tập tin một lúc giả sử hết t21 = 6 (thời gian), phần xử lý (dựa trên phần 1) t22 = 3 (thời gian).
Đó, rắc rối vậy á.
Hiện tại thì thời gian đọc file chiếm đến 95% thời gian, nên em mới tập trung vào vấn đề rút ngắn thời gian này
 
làm thế nào để xử lý song song với VBA ạ, cái này em không biết!
cách dễ dàng nhất là đầu tư mạnh về công nghệ , như lúc đầu bạn có thông tin là xử lý 100M hết 2 phút !
nếu mình có 2 máy tính , mỗi máy xử lý nửa file , thì thời gian sẽ giảm 1 nửa !
 
Hiện tại thì thời gian đọc file chiếm đến 95% thời gian
3.9 triệu dòng, 102MB hết có hơn 4 giây thôi.

1623294186092.png1623294206766.png


PHP:
Function readTextFile(ByVal strFile As String) As String
    Dim FSo As Object, txtFile As Object
    Set FSo = CreateObject("Scripting.FileSystemObject")
    Set txtFile = FSo.OpenTextFile(strFile, 1, 0, -2)
    readTextFile = txtFile.ReadAll
    txtFile.Close
    Set FSo = Nothing
    Set txtFile = Nothing
End Function
 
Thử Python hết có 0.6 giây thôi. Mỗi khi mình kêu dùng Python là tụi jav gật đầu lia lịa á. Bạn thử đề nghị với sếp xem.

1623295666319.png
 
3.9 triệu dòng, 102MB hết có hơn 4 giây thôi.
...
Máy của bạn dùng SSD? máy tôi dùng SATA đọc chậm hơn nhiều.
Nhưng bản thân tôi thì stream cả file hay từng dòng tùy theo nhu cầu chứ chả theo tốc độ.
Ví dụ nếu chỉ cần tìm vài chuõi trong file thì stream cả file, nếu cần phân biệt dòng thì stream từng dòng.

Thử Python hết có 0.6 giây thôi. Mỗi khi mình kêu dùng Python là tụi jav gật đầu lia lịa á. Bạn thử đề nghị với sếp xem.
...
Thì từ đầu toi đã nói đây là điển hình việc "đổ thừa sếp ngu" mờ.
Ba cái mớ parse text files này ai lại đi dùng đồ dỏm VBA. Còn đòi tăng tốc mới nực cười.
 
Máy của bạn dùng SSD? máy tôi dùng SATA đọc chậm hơn nhiều.
Nhưng bản thân tôi thì stream cả file hay từng dòng tùy theo nhu cầu chứ chả theo tốc độ.
Ví dụ nếu chỉ cần tìm vài chuõi trong file thì stream cả file, nếu cần phân biệt dòng thì stream từng dòng.
Theo hình thớt thêm ở bài #1 từ hôm qua thì họ cần lấy dữ liệu nằm rải rác toàn file đấy anh.
 
100 MB ... xong tới 1GB xong =====> 10GB =====> 1000 GB thì sao ???
Tôi gợi ý chút thôi ... bài số 18 link sau
 
3.9 triệu dòng, 102MB hết có hơn 4 giây thôi.

View attachment 260376View attachment 260377


PHP:
Function readTextFile(ByVal strFile As String) As String
    Dim FSo As Object, txtFile As Object
    Set FSo = CreateObject("Scripting.FileSystemObject")
    Set txtFile = FSo.OpenTextFile(strFile, 1, 0, -2)
    readTextFile = txtFile.ReadAll
    txtFile.Close
    Set FSo = Nothing
    Set txtFile = Nothing
End Function
FileSystemObject có làm việc với file bị encoding EUC-JP?
Thử Python hết có 0.6 giây thôi. Mỗi khi mình kêu dùng Python là tụi jav gật đầu lia lịa á. Bạn thử đề nghị với sếp xem.

View attachment 260389
Em cũng đề nghị rồi mà bị từ chối mới đau chứ :v
Máy của bạn dùng SSD? máy tôi dùng SATA đọc chậm hơn nhiều.
Nhưng bản thân tôi thì stream cả file hay từng dòng tùy theo nhu cầu chứ chả theo tốc độ.
Ví dụ nếu chỉ cần tìm vài chuõi trong file thì stream cả file, nếu cần phân biệt dòng thì stream từng dòng.


Thì từ đầu toi đã nói đây là điển hình việc "đổ thừa sếp ngu" mờ.
Ba cái mớ parse text files này ai lại đi dùng đồ dỏm VBA. Còn đòi tăng tốc mới nực cười.
Bình luận của anh thì em không có gì để nói :)

100 MB ... xong tới 1GB xong =====> 10GB =====> 1000 GB thì sao ???
Tôi gợi ý chút thôi ... bài số 18 link sau
Cảm ơn anh, để em tham khảo xem sao.
 
Mình cứ chép code kia vào rồi chạy, không cần chỉnh gì cả.

Tôi làm việc hàng ngày với tụi jav mà.

View attachment 260396
Lúc đầu em dung FSO rồi nhưng không dùng được. Ví dụ em muốn trích xuất tất cả các câu có chữ 領域数 và dùng chữ này làm từ khóa để tìm thì sẽ không trích xuất được câu nào cả.
Hình này là em dùng FSO đọc rồi in bằng Debug.Print, mấy câu bị lỗi là câu chứa tiếng Nhật
1623299798704.png
 
Bạn dùng fso readall để đọc nội dung file vào string rồi dùng split để tách string vào array.
Bài đã được tự động gộp:

100 MB ... xong tới 1GB xong =====> 10GB =====> 1000 GB thì sao ???
Tôi gợi ý chút thôi ... bài số 18 link sau
Cái này là xử lý text chứ có phải csdl đâu bạn.
 
Bạn dùng fso readall để đọc nội dung file vào string rồi dùng split để tách string vào array.
Bài đã được tự động gộp:


Cái này là xử lý text chứ có phải csdl đâu bạn.
CSDL hay xử lý Text thì cứ cho hết Vào SQLite xong lấy ra mà xử nhanh lắm ... thử cho 10GB vào File Text xong cho 10GB vào file CSDL SQLite xong lấy ra mà xử đi xem biết ngay và luôn thôi

CSDL SQLite hổ trợ tối đa 2048 GB ... nó lưu dưới dang byte gì đó ( ko nhớ chính xác ) nên rất nhanh
 
Lúc đầu em dung FSO rồi nhưng không dùng được. Ví dụ em muốn trích xuất tất cả các câu có chữ 領域数 và dùng chữ này làm từ khóa để tìm thì sẽ không trích xuất được câu nào cả.
Bạn chuyển tập tin đó về định dạng UTF-8 with BOM là được.

Tìm google cách chuyển nhé.
 
CSDL hay xử lý Text thì cứ cho hết Vào SQLite xong lấy ra mà xử nhanh lắm ... thử cho 10GB vào File Text xong cho 10GB vào file CSDL SQLite xong lấy ra mà xử đi xem biết ngay và luôn thôi

CSDL SQLite hổ trợ tối đa 2048 GB ... nó lưu dưới dang byte gì đó ( ko nhớ chính xác ) nên rất nhanh
Max file size khoảng 140TB thì phải. Nhưng để dùng thì còn phải import nữa.
 
Không biết FreeFile đọc file chữ Nhật Bổn và khi ghi xuống có bị mất định dạng ký tự không nhỉ? Tôi chưa có thử, chứ dùng Freefile đọc, lấy chuỗi theo yêu cầu rồi ghi ra một file Text khác cũng nhanh lắm (chừng 1, 2s đối với file text 120MB, 1tr dòng). Việc ghi lại toàn bộ file Text vừa xử lý vào Excel tôi nghĩ nhanh hơn xử lý từng dòng rồi ghi xuống Sheet.
Đối với trường hợp trên tốn thời gian là thời gian ghi xuống Sheet Excel.
 
Bạn chuyển tập tin đó về định dạng UTF-8 with BOM là được.

Tìm google cách chuyển nhé.
cách này của anh em cũng thử rồi, cách này sẽ hợp lý nếu chỉ lấy thông tin trên 1 file, còn trường hợp lấy ở nhiều file khác nhau mà vẫn dùng VBA để chuyển đổi thì tốc độ cũng không cải thiện mấy :v
 
Không biết FreeFile đọc file chữ Nhật Bổn và khi ghi xuống có bị mất định dạng ký tự không nhỉ? Tôi chưa có thử, chứ dùng Freefile đọc, lấy chuỗi theo yêu cầu rồi ghi ra một file Text khác cũng nhanh lắm (chừng 1, 2s đối với file text 120MB, 1tr dòng). Việc ghi lại toàn bộ file Text vừa xử lý vào Excel tôi nghĩ nhanh hơn xử lý từng dòng rồi ghi xuống Sheet.
Đối với trường hợp trên tốn thời gian là thời gian ghi xuống Sheet Excel.
Dính cái BOM anh ơi.
Chưa kể os tiếng jav lắm cái dị thường lắm. :)

cách này của anh em cũng thử rồi, cách này sẽ hợp lý nếu chỉ lấy thông tin trên 1 file, còn trường hợp lấy ở nhiều file khác nhau mà vẫn dùng VBA để chuyển đổi thì tốc độ cũng không cải thiện mấy :v
Bạn xem cài đặt trên phần mềm xuất logfile.txt ấy.
Hoặc đơn giản dùng tay đổi cũng được.
 
Bạn dùng Notepad tạo file trống, đặt tên là bomonly.txt, save as dưới dạng UTF-8 with BOM. Copy file này vào thư mục chứa file không có BOM, ví dụ D:\x, tạo thêm folder con D:\x\bom. Mở CMD, chạy các lệnh:
C:\>D:
D:\>cd x
D:\x>for %f in (*.*) do copy/b bomonly.txt+"%f" "bom\%f"
Các file có BOM sẽ nằm trong folder bom
 
Bạn dùng Notepad tạo file trống, đặt tên là bomonly.txt, save as dưới dạng UTF-8 with BOM. Copy file này vào thư mục chứa file không có BOM, ví dụ D:\x, tạo thêm folder con D:\x\bom. Mở CMD, chạy các lệnh:
C:\>D:
D:\>cd x
D:\x>for %f in (*.*) do copy/b bomonly.txt+"%f" "bom\%f"
Các file có BOM sẽ nằm trong folder bom

Có vẻ không hoạt động với file tạo ra bởi UNIX
1623308176576.png

D:\x>for %f in (*.*) do copy/b bomonly.txt+"%f" "bom\%f"
em hỏi thêm: cái này có giống với thao tác mở file lên rồi lưu lại với lựa chon mã hóa UTF-8 BOM không anh :v
 
Bạn thử đi hoặc gửi 1 file nhỏ lên xem.
 

File đính kèm

liên quan đến linux, em dùng ubuntu để chuyển đổi thì gặp phải ký tự ① là ubuntu báo lỗi, rồi không chuyển đổi nữa @@

Em kiếm được cái file nhỏ, các anh có thể xem qua

Cái này chỉ đổi trên máy tính của bạn thôi, sang máy tính khác vỡ nát vì không có BOM.

1623310593745.png
 
File của bạn ngăn cách bằng ký tự LF (mã 10), không phải CRLF. Mình sử dụng FSO thì vẫn thấy đọc được, không biết máy bạn lỗi ở đâu. Máy mình cũng không có font jav.
Mã:
Sub FSO1()
    Dim fso As FileSystemObject, txtFile As Object, arr
    Dim Str As String
    Set fso = New FileSystemObject
    Set txtFile = fso.OpenTextFile(ThisWorkbook.Path & "\PEC_20210603.log")
    Str = txtFile.ReadAll
    txtFile.Close
    arr = Split(Str, vbLf)
    Sheet1.Range("A1") = arr(14)
End Sub
 
Thấy befaint còn bảo làm việc thường xuyên với nó cơ!
 
Sau khi tìm hiểu thì mình thấy FSO opentextfile chỉ hỗ trợ Unicode dạng UTF 16 LE. Dùng word có thể mở file dạng EUC JP rồi saveas dạng này nhưng lưu lượng file sẽ tăng dẫn đến tốc độ load file giảm, nhất là khi dùng HDD. Vì vậy nếu bạn có SSD, thường xuyên sử dụng các file trên thì có thể thử rồi so sánh tốc độ xử lý giữa Stream và FSO.
 
File của bạn ngăn cách bằng ký tự LF (mã 10), không phải CRLF. Mình sử dụng FSO thì vẫn thấy đọc được, không biết máy bạn lỗi ở đâu. Máy mình cũng không có font jav.
Mã:
Sub FSO1()
    Dim fso As FileSystemObject, txtFile As Object, arr
    Dim Str As String
    Set fso = New FileSystemObject
    Set txtFile = fso.OpenTextFile(ThisWorkbook.Path & "\PEC_20210603.log")
    Str = txtFile.ReadAll
    txtFile.Close
    arr = Split(Str, vbLf)
    Sheet1.Range("A1") = arr(14)
End Sub
Nếu chỉ là những câu tiếng Anh thì ổn, nhưng không thể dùng tiếng Nhật để tìm kiếm thông tin được ạ.
Bài đã được tự động gộp:

Sau khi tìm hiểu thì mình thấy FSO opentextfile chỉ hỗ trợ Unicode dạng UTF 16 LE. Dùng word có thể mở file dạng EUC JP rồi saveas dạng này nhưng lưu lượng file sẽ tăng dẫn đến tốc độ load file giảm, nhất là khi dùng HDD. Vì vậy nếu bạn có SSD, thường xuyên sử dụng các file trên thì có thể thử rồi so sánh tốc độ xử lý giữa Stream và FSO.
em cũng đang tìm hướng để chuyển đổi file sang dạng có thể dùng FSO, vì em thấy FSO cho tốc độ đọc file tốt hơn ^^
 
Bạn có thể dùng vba word để open rồi saveas hàng loạt file dạng unicode utf16 LE. Trong Excel fso.opentext với tham số Tristate bằng true, tuy thời gian đọc file chậm hơn nhưng không mất thời gian chuyển đổi.
 
Dành cho ai muốn dùng ADODB.Stream để đọc từng dòng trong file cho nhanh.

Thay vì dùng câu lênh:
Mã:
ObjStream.ReadText(adReadLine)
Thì dùng câu lệnh sau:
Mã:
Dim str As String
Dim strTmp() As String
Dim lastStrTmp As String

str = ObjStream.ReadText(8192) 'Doc 8192 byte
strTmp = Split(str, vbLf)
strTmp(0) = lastStrTmp + strTmp(0)
lastStrTmp = strTmp(UBound(strTmp))
For i = 0 to UBound(strTmp) - 1
    Debug.Print strTmp(0)
Next
Thời gian đọc file 100Mb từ 2 phút sẽ có thể giảm xuống còn 10 giây.

Theo lời của tác giả thì nếu sử dụng ..(adReadLine) sẽ xảy ra hiện tượng tích lũy gì đó dẫn đến tình trạng các câu về sau càng mất nhiều thời gian để đọc. Vì vậy hãy chỉ định cho ReadText đọc một số Byte cụ thể rồi tách ra thành từng câu.

Tiện thể cảm ơn mọi người đã giúp em trong vấn đề này ^^
 
Dành cho ai muốn dùng ADODB.Stream để đọc từng dòng trong file cho nhanh.

Thay vì dùng câu lênh:
Mã:
ObjStream.ReadText(adReadLine)
Thì dùng câu lệnh sau:
Mã:
Dim str As String
Dim strTmp() As String
Dim lastStrTmp As String

str = ObjStream.ReadText(8192) 'Doc 8192 byte
strTmp = Split(str, vbLf)
strTmp(0) = lastStrTmp + strTmp(0)
lastStrTmp = strTmp(UBound(strTmp))
For i = 0 to UBound(strTmp) - 1
    Debug.Print strTmp(0)
Next
Bạn có thể up đầy đủ code được không? (có thêm file kèm thì tốt) , up thế này phải đọc lại từ đầu quá.
 
str = ObjStream.ReadText(8192) 'Doc 8192 byte
strTmp = Split(str, vbLf)
strTmp(0) = lastStrTmp + strTmp(0)
lastStrTmp = strTmp(UBound(strTmp))
For i = 0 to UBound(strTmp) - 1
Debug.Print strTmp(0)
Next[/CODE]
Thời gian đọc file 100Mb từ 2 phút sẽ có thể giảm xuống còn 10 giây.

Bạn kiểm tra lại kết quả xem có đúng không nhé. Tham số đó chỉ là để giới hạn lại số ký tự cần lấy trong một chuỗi dài thôi. File text của bạn nó sẽ ngắt ra từng 8129 ký tự thành 1 dòng (line). Muốn tham số này bao nhiêu thì bạn phải xác định độ dài chuỗi cần lấy rồi đưa vô thôi.
 
Nếu vẫn theo hướng của mình ở trên (sử dụng Word để mở file đúng định dạng rồi saveas dạng Unicode, encode UTF16 LE) thì nội dung dạng binary của file (không tính BOM) giống như chuỗi lưu trong bộ nhớ, do VB không phải decode chuỗi nên tốc độ xử lý nhanh hơn, tuy nhiên thời gian load file lại tăng do tăng dung lượng file. Hai cách lấy nội dung file vào string dưới đây cho cùng kết quả:
Mã:
Sub FSO()
    Dim fs As FileSystemObject, TxtStr As TextStream
    Dim str As String
    Set fs = New FileSystemObject
    Set TxtStr = fs.OpenTextFile(ThisWorkbook.Path & "\U16.txt", ForReading, False, TristateTrue)
    str = TxtStr.ReadAll
    TxtStr.Close
End Sub
Sub Binary()
    Dim FileNum As Integer, x() As Byte, str As String
    FileNum = FreeFile
    Open ThisWorkbook.Path & "\U16.txt" For Binary Access Read As FileNum
    ReDim x(1 To LOF(FileNum))
    Get FileNum, , x
    Close FileNum
    str = x
End Sub
 
Bạn có thể up đầy đủ code được không? (có thêm file kèm thì tốt) , up thế này phải đọc lại từ đầu quá.
bạn không cần đọc hết đâu, lấy code bài 63 sửa vào bài 1 là được, các bài khác là nhiều phương án khác nhau bạn thích thì đọc để biết thêm kiến thức ^^
Bài đã được tự động gộp:

Bạn kiểm tra lại kết quả xem có đúng không nhé. Tham số đó chỉ là để giới hạn lại số ký tự cần lấy trong một chuỗi dài thôi. File text của bạn nó sẽ ngắt ra từng 8129 ký tự thành 1 dòng (line). Muốn tham số này bao nhiêu thì bạn phải xác định độ dài chuỗi cần lấy rồi đưa vô thôi.
Đúng là nó sẽ cắt thành từng dòng như vậy, nhưng mục đích cuối là tách ra thành từng dòng như file text thì vài dòng tiếp theo sẽ xử lý. Còn về con số 8192 thì không nhất thiết phải chính xác cũng ko cần biết độ dài chuỗi cần lấy, e test qua thì thấy 8192 là tạm ổn với chương trình của e thôi.
 
Lần chỉnh sửa cuối:
Nếu vẫn theo hướng của mình ở trên (sử dụng Word để mở file đúng định dạng rồi saveas dạng Unicode, encode UTF16 LE) thì nội dung dạng binary của file (không tính BOM) giống như chuỗi lưu trong bộ nhớ, do VB không phải decode chuỗi nên tốc độ xử lý nhanh hơn, tuy nhiên thời gian load file lại tăng do tăng dung lượng file. Hai cách lấy nội dung file vào string dưới đây cho cùng kết quả:
Mã:
Sub FSO()
    Dim fs As FileSystemObject, TxtStr As TextStream
    Dim str As String
    Set fs = New FileSystemObject
    Set TxtStr = fs.OpenTextFile(ThisWorkbook.Path & "\U16.txt", ForReading, False, TristateTrue)
    str = TxtStr.ReadAll
    TxtStr.Close
End Sub
Sub Binary()
    Dim FileNum As Integer, x() As Byte, str As String
    FileNum = FreeFile
    Open ThisWorkbook.Path & "\U16.txt" For Binary Access Read As FileNum
    ReDim x(1 To LOF(FileNum))
    Get FileNum, , x
    Close FileNum
    str = x
End Sub
tiếc là cách này phải xử lý qua word :)
 

Bài viết mới nhất

Back
Top Bottom