Vọc chơi với những thuật toán nén và giải nén file
Tôi mở topic này nhằm mục đích cùng nhau nghiên cứu về nén và giải nén dùng công cụ VBA
Đầu tiên chúng ta cùng làm cuộc thí nghiệm nhỏ sau:
– Click chuột phải trên Desktop, chọn New —> WinRAR archive (hoặc WinRAR Zip archive). Đương nhiên ta sẽ nhận được một file RAR hoặc ZIP trắng
– Tiếp theo khởi động Notepad
– Dùng chuột nắm kéo file RAR (hoặc ZIP) mới vừa tạo thả vào cửa sổ Notepad
Các bạn nhìn thấy cái gì trong Notepad?
Mời trả lời rồi chúng ta sẽ tiếp tụcSao mình lại ra chữ này: PK|-
OK! những ai nhìn thấy PK|- có nghĩa là đang test với ZIP file, ngược lại là đang test với RAR file
——————-
Ở đây chúng ta bắt đầu quan tâm đến ZIP (RAR cho qua nhé)
Vậy các bạn thử thí nghiệm tiếp:
– Mở Notepad
– Gõ vào nội dung PK|-
– Lưu ý rằng ký tự "-" có charcode = 6 nha chứ không phải ký tự cạnh dấu = đâu (tốt nhất cứ copy cái PK|- hồi nảy rồi paste cho chắc ăn)
– Xong Save As lên Desktop với tên abc.zip
– Đóng Notepad và double clikc vào abc.zip xem có được không?
Mục đích cuối cùng là nén 1 file nào đó thành file ZIP hoặc giải nén 1 file ZIP ra 1 thư mục
Vậy thôi!
Tuy nhiên để nén file, nếu làm bằng tay thì dễ chứ còn code thì phải "dạy" nó từ từ:
– Tạo 1 file zip trắng (như nảy giờ bàn)
– Xong kéo file cần zip vào file zip trắng này
Vậy là ta có được file nén rồi
———————-
Nói thêm 1 chút: Với file dạng XLSX hoặc XLSM, nếu đổi đuôi thành .ZIP rồi mở lên thì ta sẽ có được 1 nội dung hoàn toàn khác đồng thời có thể làm được rất nhiều thứ bên trong nó (chẳng hạn Edit lại các file dạng xml để làm Ribbon hay xóa style, name.. vân vân…)
Ai đó thử tạo 1 NewZipFile bằng VBA như nảy giờ bàn xem!
(bằng Scripting.FileSystemObject CreateTextFile theo nội dung đã biết)Public Sub hell() Dim fso As Object, oFile As Object, strPath As String Set fso = CreateObject("Scripting.FileSystemObject") strPath = ThisWorkbook.Path & "abc.zip" Set oFile = fso.CreateTextFile(strPath) oFile.WriteLine Sheet1.Range("A1").Value oFile.Close Set fso = Nothing Set oFile = Nothing End Subkí tự char(6) không copy được lên diễn đàn hay sao ấy thầy ơi
Thì viết oFile.WriteLine "PK" & Chr(5) & Chr(6) & String(18, 0) cũng được vậy (biết charcode của nó rồi còn gì)
OK! Mình viết như vầy:
Function NewZip(ByVal ZipFile As String) As Boolean
Dim fso As Object
On Error GoTo ErrHandler
Set fso = CreateObject("Scripting.FileSystemObject")
With fso.CreateTextFile(ZipFile, True)
.Write "PK" & Chr(5) & Chr(6) & String(18, 0)
.Close
End With
NewZip = (Err.Number = 0)
Exit Function
ErrHandler: MsgBox Err.Description
End Function
Sub Main()
Dim bRet As Boolean
bRet = NewZip("D:abc.zip")
If bRet Then MsgBox "Done!"
End Sub
Phải tạo thành Function hoặc sub có tham số truyền để còn làm nhiều việc sau đó nữa
———————-
mời test thừ và cho biết kết quả rồi ta sẽ tính tiếp những bước sau
Khóa học Power PI – Ứng dung trong Nhân sự
TỔNG QUAN KHÓA HỌC: POWER BI CHO NGÀNH NHÂN SỰ Khóa học Power BI cho Nhân sự được thiết kế dành riêng cho các...
Xem khóa học
Tôi nhớ không lầm thì để làm ribbon người ta tạo ra file CustomUI.xml với cả đống lệnh trong đó. Vậy nên tôi có ý tưởng:
– Dùng VBA tạo ra cái đống lệnh rồi Save thành file CustomUI.xml
– Tiếp theo bằng phương pháp nén file (như chủ đề topic này) ta sẽ đưa CustomUI.xml vào bên trong file xlsm
Quy trình là vậy nhưng để thực thi nó thì vẫn còn nhiều bước lắm. Từ từ chúng ta cùng nghiên cứu vậy!
(Tôi ghét ribbon bởi luôn phải có công đoạn làm bằng tay. Nếu như toàn bộ đều bằng code thì.. chuyện ngon rồi).
"Công trình" đầu tiên
Đây là "công trình" đầu tiên của việc nén file:
Mời test thử và cùng hoàn thiện
Lưu ý quan trọng(mất công các bạn tự làm bị lỗi mà không biết): Mấy cái biến màu đỏ tuy ta có thể dùng như chuỗi nhưng tuyệt đối không được khai báo nó dạng chuỗi (kiểu như Dim FilePath as String)… nếu không code lập tức báo lỗi. Các bạn có thể thay đổi 1 vài biến màu đỏ thành dạng As String và test thử
———————————-
Tôi nghiên cứu tới đâu đăng bài tới đó chứ chưa có gì sẵn trong đầu cả (chỉ có ý tưởng)… vậy nên xin mời các bạn góp sức hoàn thiện (tôi tin chắc vẫn còn lỗi ở đâu đó)
Cảm ơn
Mình thật may mắn khi luôn có các bạn đồng hành! Cảm ơn
—————————————————————–
Tôi test thử trên Windows 7 (32bit) + Office 2010 (32bit) thì cả 2 cách trên đều được
Vậy mời các bạn khác test thử, nếu thay đổi như anh Chim Hồng mà không máy nào báo lỗi thì ta sẽ thống nhất dùng code này
(mục đích để máy nào cũng dùng được)
Trên máy tôi thì nó là tên cái file cần nén
Ẹc… Ẹc… ứ biết cái gì trong trái ổi… Mò là chính, mò hoài không ra thì.. hết gân!
Mình nghĩ từ bước 4 trở đi sẽ là:
4> Mang file CustomUI.xml đưa vào trong file xlsx.zip hoặc xlsm.zip (thủ tục nén file)
5> Đổi đuôi xlsx.zip hoặc xlsm.zip thành xlsx hoặc xlsm
Cố tình muốn xử lý theo kiểu chuỗi đấy mà (tại vì biến ở trên ta khai báo Variant)
Tại cái tật cẩn thận (muốn làm cái gì ra cái đó)
Ẹc… Ẹc…
Thì tiêu chí từ đầu của tôi là… TỪ TỪ mà (đừng nóng vội sẽ hư bột hư sugar)… từ từ và chắc corn –=0
Tôi chỉ nêu cái "viễn cảnh" gây "kích thích" thôi!
Vừa test lại xong, đổi qua lại giữa 2 code, tất cả đều bình thường Thắng à!
Hết hồn (nhưng mọi thứ.. còn nguyên)
—————————————-
Chỗ này là mình sơ sót, ở trong Items.Item(…) phải là 1 name chứ không thể fullname
Đã vậy thì bỏ luôn sFile cho rồi (hoặc bỏ sName chứ ai lại sFile = sName)
OK!
Vậy chúng ta cùng test theo hàm vừa sửa nhé:
Xem thử còn lỗi gì nữa không?
Cái vụ đó bỏ qua! Bởi mục đích chính của ta hoàn toàn không phải muốn thay thể chương trình WinRAR hay WinZIP. Điều ta cần cuối cùng là EDIT FILE XML NẰM TRONG FILE XLSX, XLSM
Như chủ đề topic, ta đã nén được rồi thì giờ tiên hành giải nén
(tuy nhiên các bạn khác cứ test thử code bài 61 xem còn lỗi gì không đã)
Theo tiêu chí mà ta đang hướng tới thì code cần hoàn thiện là:
– Code có khả năng nén 1 file vào trong 1 file zip có sẵn (nếu file zip chưa có thì mới tạo NewZip)
– Code có khả năng giải nén 1 file chỉ định nào đó bên trong file zip đang chứa nhiều files khác (có thể ta chỉ cần edit 1 file nào đó trong file zip mà thôi)
Cơm xong uống nước lọc thôi, đừng uống nước cái —> "bay" hổng nỗi luôn đóa –=0
Kết quả test:
– Chạy lần đầu, chọn file b1.xlsx nó ra kết quả b1.xlsx nằm trong b1.zip
– Chạy lần hai, vẫn chọn file b1.xlsx nó ra kết quả b1.xlsx nằm trong b1.xlsx.zip
Trong khi câu lệnh của ta là:
Đã chỉ rõ nơi đến thì lần đầu chạy hay lần hai cũng phải cho cùng kết quả chứ nhỉ?
Mới thử sơ qua —> Kết quả ngon
Giờ phải vào ca 3, tối nay nếu rảnh sẽ test tiếp
Tôi đoán rằng code ở bài 80 và 86 có thể không cần đối số seekPath
Thử xem liệu có được không?
Tốt nhất làm sao cả 2 hàm chỉ cần 2 đối số: Nguồn và Đích
Lấy thư mục "do choi" của bạn hôm qua làm ví dụ nhé:
Hoặc vầy:
đều được!
Màu xanh là nguồn, màu đỏ là đích
Thử xem được không
Thì 2 cái màu xanh ráp lại là thành nguồn (khi dùng ta chỉ cần truyền vào path & "b1.xlsx.zipxlstyles.xml" là được rồi)
Việc của ta là "cắt" sao đó để phân cái nguồn này thành 2 để ráp code thôi
Mới "ý tưởng" thôi (vì thí nghiệm thấy được), lấy gì "múa" đây
Tôi cũng có nghĩ đến chuyện này rồi (cũng chỉ ý tưởng): Ta viết luôn 2 dòng:
Nếu không được thằng trên thì nhảy xuống thằng dưới
Chẳng biết nữa, phải thử rồi tính
(nói chung lúc code mình có thể cực chút, miễn sao lúc dùng thoải mái nhất là ngon! Nhiều đối số truyền quá rất khó hình dung)
Cách test hữu hiệu nhất là đưa vào thực nghiệm
Tôi đã viết xong thủ tục xóa styles rác từ đường dẫn file styles.xml cho trước:
Các bạn có thể sửa thủ tục trên thành hàm để trả về giá trị gì đó nếu cần
————————————
Giờ bắt đầu thử nghiệm:
– Đầu tiên ta sẽ tìm đâu đó một file có nhiều styles rác (trên diễn đàn có đầy). Tiếp theo nếu file chứa styles rác này có định dạng .xls thì hãy mở file SaveAs thành .xlsx (hoặc .xlsm), sau đó bắt đầu viết thêm 1 code làm việc theo quy trình 5 bước sau:
1> Đổi đuôi file .xlsx (hoặc xlsm) thành .xlsx.zip (hoặc .xlsm.zip)
2> Dùng hàm giải nén file .xlsx.zip (hoặc .xlsm.zip) để lấy ra file styles.xml
3> Dùng code tôi viết ở trên để làm sạch style rác
4> Dùng hàm nén file để đưa file styles.xml vào lại trong file .xlsx.zip (hoặc .xlsm.zip)
5> Đổi đuôi file .xlsx.zip (hoặc .xlsm.zip) trở lại thành .xlsx (hoặc .xlsm)
– Mở bằng tay file .xlsx (hoặc .xlsm) kiểm tra xem các styles rác đã thật sự được làm sạch hay chưa?
————————————
Lưu ý quan trọng: Từ bước 2 đến bước 3 có khả năng xảy ra lỗi. Lý do vì quá trình giải nén tại bước 2, file styles.xml chưa kịp hình thành nên không thể xử lý xóa styles tại bước 3. Vậy bằng cách nào đó ta hãy làm trễ bước 2 khoảng 1 vài giây rồi hẳn tiếp bước 3 (Dùng Application.Wait chẳng hạn)
Nói chung mọi thứ đã có, giờ hãy thí nghiệm để kiểm chứng thành quả nhé
Cảm ơn!
Mở file styles.xml bằng Notepad là thấy chứ cần gì giải thích
– Tìm trong styles.xml những chuỗi dạng <cellStyle name="Tên của style" ………/>
– Nếu thấy từ khóa builtinId bên trong <cellStyle name="Tên của style"…… builtinId… /> thì đó là style có sẵn
– Nếu không tìm thấy từ khóa builtinId thì đó là style rác và ta sẽ xóa nó
Nói thêm: Ở đây ta mượn tạm sub xóa styles để test mấy công cụ nén và giải nén. Nếu nó hoạt động tốt thì ta xem như công cụ của ta tốt
Đương nhiên, việc edit styles bên trong file styles.xml các bạn có thể viết kiểu khác tùy ý
Tôi kiểm tra đâu thấy "đi đời" gì đâu, chỉ là file xlsx ấy còn y nguyên 2 styles rác
Còn 1 chuyện nữa: Nếu file cần xóa styles, sau khi qua xử lý nhận đươc thông báo "không có styles rác nào" thì ta bỏ qua công đoạn nén file luôn chứ
Bởi vậy tôi cẩn thận gợi ý lần trước rằng:
Dựa vào kết quả mà hàm trả về, ta biết được có styles rác hay không rồi mới tính tiếp
Tôi sửa sub ClearStylesFromXML thành Function ClearStylesFromXML
Đồng thời sửa 2 sub cuối thành:
Các bạn test thử xem!
Kỳ vậy ta? Mình test nó chạy phà phà luôn ấy chứ
Thử đổi câu lệnh:
Thành:
và test lại xem sao
(đang nghi thằng Popup có vấn đề)
File đính kèm dưới đây là kết quả sau khi chạy code tại máy mình. Bạn tải về xem thử có mở được trên máy bạn không nha? Nếu như mở được thì kiểm tra xem còn styles rác nào không?
Chờ kết quả
Ta có thể phân ra từng công đoạn để test:
– Dùng code giải nén file xlsx để lấy ra file styles.xml
– Dùng code xóa styles rác
– Dùng code nén file styles.xml (đã được xóa styles) vào lại file xlsx
Test riêng từng công đoạn một để biết vấn đề nằm chỗ nào
————————-
Thì cứ thử theo bài 114 xem. Phân từng đoạn để test xem vấn đề nằm ở đâu (gọi là "khoanh vùng đối tượng") –=0
nó đây nè . hôm bữa tôi nhìn tổng dung lượng tối đa của tôi là 15MB . sao hôm nay tự nhiên tăng lên thành 50MB kì vậy ta ?
vậy rốt cục là sao ?
xin phép được viết lại hàm xóa Style rác trong file xml của thầy NDU
cách này chắc sẽ chậm hơn cách của thầy . Nhưng được cái dễ xài hơn . hi hi
Ủa! Mình tưởng "đồ chơi" như vậy là đủ rồi chứ, giờ muốn làm cái gì các bạn tự sáng tạo thôi
Thì tôi cũng có hiểu cấu trúc xml gì đâu trời! Toàn đoán và mò thôi mà. Mọi người cũng cùng.. mò xem có gì lạ trong xml thì hãy chia sẻ