Lỗi Encoding Unicode khi xuất dữ liệu từ Excel sang Notepad

Liên hệ QC

casanova2008

Thành viên mới
Tham gia
9/5/09
Bài viết
1
Được thích
0
Chào cả nhà, mình đang muốn xuất dữ liệu từ Excel sang Notepad với mỗi cột của hàng 1 là tên file và mỗi cột của hàng 2 là nội dung. Mình có tìm được đoạn mã dưới đây nhưng khi xuất ra thì bị lỗi font chữ. Qua tìm hiểu thì mình nghĩ là do Notepad mặc định encoding là ASCII nên mới bị vậy. Xin mọi người xem và bổ sung thêm đoạn code này để xuất bằng encoding Unicode được không ạ. Xin cảm ơn nhiều.

Sub ExportToNotepad()
Dim wsData As Variant
Dim myFileName As String
Dim FN As Integer
Dim p As Integer, q As Integer
Dim path As String
Dim myString As String
Dim lastrow As Long, lastcolumn As Long

lastrow = Sheets("sheet1").Range("A" & Rows.Count).End(xlUp).Row
lastcolumn = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
path = "D:\Jobs\"

For p = 1 To lastcolumn
wsData = ActiveSheet.Cells(1, p).Value
If wsData = "" Then Exit Sub
myFileName = wsData
myFileName = myFileName & ".txt"
myFileName = path & myFileName
MsgBox myFileName
For q = 2 To lastrow
myString = myString & " " & Cells(q, p)

FN = FreeFile
Open myFileName For Output As #FN
Print #FN, myString
Close #FN
Next q
myString = ""
Next p

End Sub
 
Bạn ngâm cứu dùng ADODB.Stream để đọc và ghi file text đi. Nó có thuộc tính Charset để chuyển đổi file text sang dạng charset mong muốn (ví dụ: "utf-8".
Code đại khái như sau, bạn chỉnh lại theo dữ liệu của bạn.
(tôi dùng khai báo sớm thư viện ADODB cho nhanh, sau này bạn tự sửa thành late binding)

Mã:
Option Explicit

Function export2txt()
    Dim fileStream As ADODB.Stream
    Dim strChuoiXuat As String
    Const FileName As String = "myfile.txt"

    Set fileStream = New ADODB.Stream
    strChuoiXuat = "chuoi mà bạn đã xử lý"
    With fileStream
        .Type = adTypeText     'Thuoc tinh Charset chi dùng được cho 'adTypeText'
        .Charset = "utf-8"
        .Open
        .WriteText strChuoiXuat
        .SaveToFile FileName, adSaveCreateOverWrite
        .Close
    End With
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Cách thì có nhiều, vd. dùng đối tượng FileSystemObject, có thể tìm trên GPE, trên mạng.

Tôi có tham vọng khác. Đó là chỉ ra những khúc mắc trong chính code mà bạn dùng. Không có cách học nào tốt hơn cách học trên chính lỗi của mình.

Điểm quan trọng nhất là dòng
Mã:
m = myString
với m là mảng BAI.

Về Open ... Close của VBA bạn vẫn có thể dùng được. Chỉ cần sửa 2 dòng
Mã:
Open myFileName For Output As #FN
Print #FN, myString

Nhưng tôi thấy là gọi Open ... Close trong vòng lặp For q = ... là không lôgíc, không tối ưu. Vì lúc đó mỗi tập tin sẽ được ghi (lastrow-1) lần, lần ghi sau sẽ xóa lần ghi trước. Tốn điện và nước.

Vẫn là code của bạn, tôi chỉ sửa những điểm chính.
Mã:
Sub ExportToNotepad()
Dim wsData As Variant
Dim myFileName As String
Dim FN As Integer
Dim p As Integer, q As Integer
Dim path As String
Dim myString As String
Dim lastrow As Long, lastcolumn As Long, m() As Byte

lastrow = Sheets("sheet1").Range("A" & Rows.Count).End(xlUp).Row
lastcolumn = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
path = "D:\Jobs\"

For p = 1 To lastcolumn
    wsData = ActiveSheet.Cells(1, p).Value
    If wsData = "" Then Exit Sub
    myFileName = wsData
    myFileName = myFileName & ".txt"
    myFileName = path & myFileName
    MsgBox myFileName
    For q = 2 To lastrow
        myString = myString & " " & Cells(q, p)
    Next q
    m = myString
    FN = FreeFile
    Open myFileName For Binary As #FN
    Put #FN, , m
    Close #FN
    myString = ""
Next p
End Sub
 
Upvote 0
Lưu xuống file thì code nào cũng đúng, lưu được cả, các string đều là Unicode string, nhưng lại lưu sai cấu trúc của Unicode Text File, nên notepad mở ra theo Ansi Format.
Hì hì, nói vắn tắt là nó bị thiếu BOM đó :)
 
Upvote 0
Hỏi ông Gấu gồ đó: BOM Unicode file
Dùng 1 hex editor, mở file text Unicode lên, sẽ thấy ông BOM là gì, ngay đầu file đấy
 
Upvote 0
Không phải thiếu BOM mà notepad hiển thị sai. Code của tôi có ghi BOM đâu nhưng notepad vẫn mở lên chuẩn.

Nói chung BOM là để phân biệt, nhận dạng. Nhưng không có BOM thì nếu ruột đúng là unicode thì notepad 100% phát hiện ra và hiển thị đúng, nếu ruột đúng là UTF-8 thì nhất định nó nhận ra và hiển thị đúng. Vì BOM chỉ là dấu hiệu chứ không phải không có BOM là bó tay.

Có BOM mà "ruột" không là unicode hay UTF-8 thì càng tai hại. Nếu "ruột" không là unicode hay UTF-8 mà cố tình thêm BOM thì chỉ tai hại thêm. Ruột đã không là unicode hay UTF-8 thì không thể chỉ đơn giản thêm BOM là tự dưng nó trở thành unicode hay UTF-8 được. Suy nghĩ kiểu này giống như: tôi có tập tin ảnh "hichic.txt". Tôi phải chuột rồi Rename thành "hichic.jpg". Thế là tôi có ảnh. Không đơn giản thế được. :D

Tập tin mà code của tôi ghi ra làm gì có BOM? Nhưng notepad vẫn nhận ra và hiển thị đúng. Nếu ai còn nghi ngờ khả năng nhận biết của nó thì sau khi mở tập tin mà code của tôi tạo ra thì chọn File -> Save As. Trong cửa sổ "Save As" notepad đã chọn sẵn và đề nghị encoding = unicode. Nếu lúc này nhấn Save thì notepad sẽ thêm BOM = FFFE vào đầu tập tin. Vì những ứng dụng chuẩn luôn ghi BOM (dấu hiệu).

Nếu ai còn chưa cảm thấy thuyết phục thì tải tập tin tôi đính kèm ở dưới. Sẽ chỉ có 1 tập tin với tên A1 = test và nội dung A2 = "sướng". Có 2 nút để tạo tập tin có BOM và không có BOM. Code là của chủ chủ đề. Tôi chỉ sửa để thêm 2 bai BOM FFFE (unicode), và để thêm tiền tố "coBOM" và "khongBOM" vào tên tập tin.

Code trong tập tin là của tác giả
Mã:
Option Explicit

Sub ExportToNotepad(ByVal prefix As String)
Dim wsData As Variant
Dim myFileName As String
Dim FN As Integer
Dim p As Integer, q As Integer
Dim path As String
Dim myString As String
Dim lastrow As Long, lastcolumn As Long

lastrow = Sheets("sheet1").Range("A" & Rows.Count).End(xlUp).Row
lastcolumn = ActiveSheet.Cells(1, Columns.Count).End(xlToLeft).Column
path = "D:\"

For p = 1 To lastcolumn
    wsData = ActiveSheet.Cells(1, p).Value
    If wsData = "" Then Exit Sub
    myFileName = wsData
    myFileName = prefix & "_" & myFileName & ".txt"
    myFileName = path & myFileName
    MsgBox myFileName
    For q = 2 To lastrow
        If prefix = "coBOM" Then
            myString = Chr(&HFF) & Chr(&HFE) & myString & " " & Cells(q, p)
        Else
            myString = myString & " " & Cells(q, p)
        End If
        FN = FreeFile
        Open myFileName For Output As #FN
        Print #FN, myString
        Close #FN
    Next q
    myString = ""
Next p

End Sub

Sub khongBOM()
    ExportToNotepad "khongBOM"
End Sub

Sub coBOM()
    ExportToNotepad "coBOM"
End Sub


BOM.JPG
 

File đính kèm

Upvote 0
notepad dùng hàm API IsTextUnicode để detect content file khi không có BOM. Hàm API này không luôn chính xác, vì vậy mới có vụ thêm BOM hay không BOM.
File của testBOM lưu xuống có BOM, mà content lại là Ansi string, chả trách thằng notepad mở sai.
PS: Lưu link này lại để khỏi mất công Google Online Free Hex Editor
 
Lần chỉnh sửa cuối:
Upvote 0
Vụ unicode tôi biết khá nhiều nhưng tôi không muốn tranh luận.

Chỉ có 1 vấn đề.

Chủ chủ đề tung ra code và than phiền là notepad không đọc ra được.

- Tôi khẳng định là notepad không đọc ra được là do cách ghi sai.

- Bạn khẳng định là notepad không đọc ra được là do thiếu BOM.

Vậy tôi lấy code của chủ chủ đề và chỉ thêm BOM.

Như bạn thấy thì có BOM theo bạn notepad cũng vẫn bó tay. Vì nội dung không là unicode thì có thêm BOM cũng thế thôi. Còn đầu trâu mặt ngựa hơn. Mà nội dung không là unicode thì là do cách ghi. Tôi khẳng định là mấu chốt ở cách ghi.
File của testBOM lưu xuống có BOM, mà content lại là Ansi string, chả trách thằng notepad mở sai.
Thì đấy là nội dung do code của CHỦ CHỦ ĐỀ đưa ra mà. Người ta than phiền mà bạn nói lý do là không có BOM, chứ bạn có nói lý do là do cách ghi đâu?

Chỉ có tôi nói nguyên nhân là do cách ghi. Bạn nói là do thiếu BOM. Bây giờ bạn lại kêu là nội dung là ansi nên không đọc được. Vậy câu hỏi tu từ: Code của chủ chủ đề sai ở đâu? Ở cách ghi nội dung vào tập tin như tôi chỉ ra hay là do thiếu BOM như bạn nói?
 
Upvote 0
Code của bác vẫn sai, chưa hoàn thiện vì ghi thiếu BOM. May là notepad mở được đó, chứ các text editor khác liệu mở được không ?
Không nói chi đâu xa, ngay trong ứng dụng WordPad của Windows đấy, thiếu BOM nó vẫn mỡ sai tè le, trong khi Notepad mở đúng.
File đính kèm là file Unicode, nhưng thiếu BOM, các bác mở thử trong notepad và wordpad thử nhé. Chọn font thỏa mái.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Code của bác vẫn sai, chưa hoàn thiện vì ghi thiếu BOM. May là notepad mở được đó, chứ các text editor khác liệu mở được không ?
Không nói chi đâu xa, ngay trong ứng dụng WordPad của Windows đấy, thiếu BOM nó vẫn mỡ sai tè le, trong khi Notepad mở đúng.
File đính kèm là file Unicode, nhưng thiếu BOM, các bác mở thử trong notepad và wordpad thử nhé. Chọn font thỏa mái.
Có 2 nút. Nhấn nút "Ghi BOM" rồi mở bằng Hex Editor" thì sẽ thấy BOM = FFFE. Không có BOM thì có lẽ do ma, vì nhìn code cũng thấy có ghi BOM.
 
Upvote 0
Mình nói code bác viết ở trên đó, dùng Put binary đó bác à.
 
Upvote 0
Lưu xuống file thì code nào cũng đúng, lưu được cả,
Bạn nhầm rồi.

- Vẫn tập tin ở bài #7 mà nhấn "Khong ghi BOM" (code của chủ chủ đề) thì khi mở bằng Hex Editor sẽ có "20 73 75 6F B4 6E 67 0D 0A". Đây rõ ràng không là unicode format.

- Vẫn tập tin ở bài #7 mà chạy code của tôi ở bài #3 (code của tôi) thì khi mở bằng Hex Editor sẽ có "20 00 73 00 B0 01 A1 01 01 03 6E 00 67 00". Đây rõ ràng là unicode format.

"20 00" là ký tự dấu cách có điểm mã là &H0020 (trong windows thì mặc định là low byte/word ghi trước high byte/word) = 32

"73 00" là ký tự có điểm mã là &H0073 = 115 -> ký tự "s"

"B0 01" là ký tự có điểm mã là &H01B0 = 432 -> ký tự "ư"

"A1 01" là ký tự có điểm mã là &H01A1 = 417 -> ký tự "ơ"

"01 03" là ký tự có điểm mã là &H0301 = 769 -> ký tự dấu sắc (xem hình: 0301 -> dấu sắc)

Do dấu sắc là dấu thanh nên lúc này nó được ghép với "ơ" ở trước thành "ớ". "ớ" này là unicode tổ hợp - tổ hợp của "ơ" và ký tự dấu sắc. Ngoài 'ớ" tổ hợp này trong bảng mã unicode còn có ký tự "ớ" chỉ dùng 2 bai (thay cho 4 bai ở trên). Ký tự có điểm mã &H1EDB = 7899 -> ký tự "ớ" (xem hình). Đây là "ớ" dựng sẵn, được biểu diễn chỉ bằng 2 bai 1E và DB

"6E 00" là ký tự có điểm mã là &H006E = 110 -> ký tự "n"

"67 00" là ký tự có điểm mã là &H0067 = 103 -> ký tự "g"

Tóm lại chuỗi bai "20 00 73 00 B0 01 A1 01 01 03 6E 00 67 00" là "sướng"

Vậy khẳng định
Lưu xuống file thì code nào cũng đúng
là không đúng. Rõ ràng nội dung do code của chủ chủ đề ghi ra không có dạng unicode trong khi nội dung do code của tôi ghi ra có định dạng unicode. Đánh đồng 2 code là chưa hiểu được bản chất của vấn đề.
các string đều là Unicode string,
Rõ ràng không đúng. Nội dung từ code của chủ chủ đề không có dạng unicode. Tập tin từ code của tôi có dạng unicode như tôi đã chỉ tỉ mỉ ở trên.
nhưng lại lưu sai cấu trúc của Unicode Text File, nên notepad mở ra theo Ansi Format.
Nếu khẳng định là sai cấu trúc của Unicode Text File cho cả 2 tập tin thì chưa hiểu unicode. Unicode thì luôn là unicode cho dù có BOM hay không. Có BOM thì dễ nhận dạng. Cũng như nếu nội dung đã là TEXT thì dù tên là "hichic.txt" hay đổi tên thành "hichic.jpg" thì bản chất nó vẫn là văn bản. Anh A có mặc váy, tô môi, phi dê thì lõi vẫn là "đực". Cách đây mấy ngày có người không mở được tập tin "xyz.xlsx". Tôi chỉ ra là lõi nó là tập tin ảnh chứ không phải là tập tin Excel.


bangma.JPG


bangma1.JPG
 
Upvote 0
Hì hì, dông dài chi cho mệt, bắt lỗi câu chữ
Bác mở file test.txt tôi up trong hex editor, notepad, wordpad, word thì thấy.
 
Upvote 0
Mình nói code bác viết ở trên đó, dùng Put binary đó bác à.
Code của tôi không ghi BOM nhưng nội dung là unicode như tôi chỉ ra ở bài #13. Và mở ra bằng notepad xem chuẩn. Tôi dùng Excel 2010 32 bit + XP Home + Servece Pack 3. Nhưng tôi nghĩ không phụ thuộc vào system.
Bài đã được tự động gộp:

Hì hì, dông dài chi cho mệt, bắt lỗi câu chữ
Vì những khẳng định đó là không đúng. Đánh đồng 2 code là không đúng.
Bác mở file test.txt tôi up trong hex editor, notepad, wordpad, word thì thấy.
Úp trong bài nào? Tôi không thấy
 
Lần chỉnh sửa cuối:
Upvote 0
Có lẽ tôi đã viết hết ý rồi. Tôi chấm dứt tại đây. Tôi chỉ đính kèm tập tin video để mọi người kiểm nghiệm. Tôi chạy code của tôi với tập tin tại bài #7. Trước khi chạy code thì thư mục "C:\Test" rỗng. Tôi chỉ ra bằng chuột là code sẽ lưu tập tin ở thư mục "C:\Test\". Sau khi chạy code thì trong "C:\Test\" có tập tin Test.txt. Tôi mở bằng notepad thì nhìn thấy " sướng" (dấu cách ở đầu là do code thêm), tức y như A2 trong Excel. Khi mở bằng Hex Editor thì thấy chuỗi bai "20 00 73 00 B0 01 A1 01 01 03 6E 00 67 00".

Chuỗi trên là unicode tổ hợp. Tại sao? Tôi không dùng Unikey mà dùng bàn phím của Windows để gõ tiếng Việt trong A2. Khi gõ bằng bàn phím này thì sẽ ra unicode tổ hợp vì system dùng unicode tổ hợp. Nếu ai đó dùng Unikey và chọn bảng mã Unicode thì sẽ gõ vào A2 unicode dựng sẵn (nếu tôi không lầm, tôi không dùng Unikey). Lúc đó chuỗi bai sẽ hơi khác. Nhưng đều là unicode và 100% sẽ xem được.
 

File đính kèm

Upvote 0
Mà xuất sang note pad, không Ctrl+C (excel) rồi Ctrl+V(note pad) là xong việc chi code,
Hoặc cùng lắm xuất file CSV là xong, hay file tab
 
Upvote 0
Web KT

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

Back
Top Bottom