0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[VBScript]令和最強のデータテキスト形式はタブ区切りUTF-16LE形式というのをCscript名前付き引数ファイルリストを作って証明

Last updated at Posted at 2020-09-06

タブ区切りとは

あまり知られていませんが、Excelはタブ区切りとコンマ区切りという2つのテキスト形式を読み書きできます。
よく知られているのはコンマ区切り形式です

Name,Value,Date
"A","2,000","2000/01/01"

しかしコンマは金額でも使うものです。このためエスケープとしてダブルクォーテーションで囲む必要がありました。

Tsvは誤読されない

タブ文字(vbTab)は一般的に使われず、さらにスペースで代用できます。このため、タブ区切りは区切り文字以外には使用されていない可能性が高いため誤った区切りになる可能性が低いと言えます。

Name Value Date
"A" 2,000 2000/01/01

Qiitaではマークダウンでコード表示にすると	が表示されます。

Name	Value	Date
"A"	2,000	2000/01/01

メモ帳(Notepad.Exe)でExcelファイルが作れる

TAB区切りで作り、UTF-16でtsvかテキストに保存すれば出来上がります。
このため、スマホやExcelがないPCでもExcelデータが作成できます。
このときコンマ付き数字が使えるという点が役立ちます。

多言語対応はできるが従来はBOM有り、BOMなしの問題があった

多言語文字を文字化けせずにCSV形式で出力するには? Re*Programing 2010/05/01

仕事で多言語サイト作成でハマった所を一つ。
内容は、多言語表示した表(文字)をCSVでダウンロード出力する。といった内容だったのですが。。。
(中略)
が、気の早いあなたには、先に結論を。
タブ区切りのUTF16LE(リトルエンディアン):Bom付で出力してあげればOKです。
これでcsvファイルのダブルクリックでちゃんと文字化けせずに読み込めます。

ただ、検証環境は要件からWindows + Excel2000です。
新しいEccelやMacOfficeは検証していません。
というか、検証してくださるとありがたい><
2010/05/10追記
Office 2008 for Mac:評価版でも正常に開ける事を確認しました。

しかしExcelはBOMの有無に関わらず読めるようになったためWin/MACの壁もなくなった

Win/Mac どちらの Excel でも正しく開ける Unicode な csv の出力方法

Excel for Mac 2016 のあるアップデートから UTF8-BOM が開けるようになったようです。
https://www.ka-net.org/blog/?p=7764
Office 2016の10月の機能更新によって、ExcelでUTF-8文字エンコードのCSVファイルがサポートされるようになりました(バージョン 1610(ビルド 7466.2038)以上)。

まだ CSV の文字化けで消耗してるの?(Excel で直接開いても文字化けしない CSVファイルを Python3 で作成するスマートな方法) 2017/12/09

そもそもUTF-16LEにはBOM付与は許されない

符号化スキームにはUTF-16、UTF-16BE、UTF-16LEの3種類ある。UTF-16BEは16ビット整数をビッグエンディアンで直列化する。UTF-16LEはリトルエンディアンで直列化する。UTF-16BE、UTF-16LEの場合はバイト順マーク (BOM) の付与は許されない。UTF-16の場合はBOMでエンディアンを明示するか、上層のプロトコルで指定されておらずBOMも付与しない場合はビッグエンディアンにするよう決められている[1]。

ここがUTF-16ならBOMの問題が生じるがLEであれば生じない。このためUTF-16LEにはBOMの問題は生じない。

UTF-16LEならFilesystemObjectで書ける

FilesystemObjectはUTF-16LEでTextStremを作成できます。
ExcelからExportするときもFilesystemObjectを使うとUTF-16になります。

UTF-16だとADODB.Streamを使わない

このため
コードがかんたんになり、誤りが少ない。
早い。
というメリットしか有りません。

Option Explicit
' VBScriptでファイル一覧作成 https://qiita.com/nobu-maple/items/20c675f9c8f4db55b4c0
'【VBS】Format関数の@書式を作ってみた https://qiita.com/yaju/items/8e07c8c6d9eeda316cd6
' FormatDateTIme関数 https://www.kanaya440.com/contents/script/vbs/function/string/format_datetime.html
' 引数を受け取る方法 https://bayashita.com/p/entry/show/79
' 使用方法 %USERPROFILE%\Documents\CscriptCurrentDirFileListUTF16LEN.vbsとする
' CMDを起動する。
' CurrentDirectryへ移動する
' Cscript.exe "%USERPROFILE%\Documents\CscriptCurrentDirFileListUTF16LEN.vbs /Ext:pdf /MaxMinutes:60 /MaxFilesCount:20000
' 名前付き引数 /Ext:pdf 拡張子 /MaxMinutes:60 処理時間(分) 最大24時間 /MaxFilesCount:20000 最大ファイル数(LimitFileCount = 10000 以上初期設定限界値LimitFileCount=500000)
Const ForReading = 1 'AS Long
Const ForWriting = 2 'AS Long
Const ForAppending = 8 'AS Long
Const WindowsFolder = 0 'AS Long
Const TemporaryFolder = 2 'AS Long
Const UTF16True = -1 'As Boolean vbTrue
Const vTristateFalse = 0
Const vTristateTrue =-1
Const vTristateMixed =-2
Const vTristateUseDefault =-2
Const LimitFileCount = 100, cnsMaxFilesLimit = 500000
Const cnsLimitTime = 30, cnsMaxLimitMinutes=1440 'Minutes
Const TsvFileFolder = "H:\"
'// INIT
  Dim FSO
  Dim TS
  Dim DT , DT2
  Dim strDate
  Dim testFolder
  Dim blResult : blResult = False
  Dim CNT, intArgsCount : CNT = 0
  Dim WSH : Set WSH = WSCript.CreateObject("WSCript.Shell")
  Dim tgFolder
  Dim ObjNamed
  Dim ArgFilesLimite 'AS Double
  Dim ArgMinutesLimit 'AS Long
DT = Now
Set FSO = WScript.CreateObject("Scripting.FileSystemObject")
  Dim str
'Listを作るフォルダが無ければ終了
IF FSO.FolderExists(TsvFileFolder) = vbFalse Then WScript.Echo "Line0034:TsvFileFolder (" & TsvFileFolder & ") Not Exists. End" : Wscript.Quit
If Len(Hour(DT)) =1 then strDate = Replace(FormatDateTime(DT,vbShortDate),"/","",1,-1) & "0" & Replace(FormatDateTime(DT, vbLongTime),":","",1,-1) Else StrDate = Replace(FormatDateTime(DT,vbShortDate),"/","",1,-1) & Replace(FormatDateTime(DT, vbLongTime),":","",1,-1)
Set Ts = Fso.OpenTextFile(TsvFileFolder & "\FileList" & strDate & ".tsv" , ForWriting, True, vTristateTrue)
Ts.WriteLine "ファイル名" & vbTab & "作成日時" & vbTab & "更新日時" & vbTab & "サイズ" & vbTab _
& "属性" & vbTab & "拡張子" & vbTab & "ファイルタイプ" & vbTab & _
"ショートファイル名" & vbTab _
& "フォルダパス" & vbTab & "フォルダショートパス"
'// Main
str = FSO.Getfolder(".")
IF WScript.Arguments.Named.Count > 0 Then
Set objNamed = WScript.Arguments.Named
Wscript.Echo "Line:0051" & vbTab & ObjNamed.count
End IF
' 最大時間(分)制限
' cnsLimitTimeより小さければcnsLimitTime。cnsMaxLimitMinutes(初期値:24時間(1440分)より大きければ24時間
On Error Resume Next
IF IsEmpty(objNamed) =vbFalse And ObjNamed.Exists("MaxMinutes") And objNamed.Item("MaxMinutes") <> "" Then
IF cnsLimitTime >= CLng(objNamed.Item("MaxMinutes")) Then 
ArgMinutesLimit= cnsLimitTime
ElseIF CLng(objNamed.Item("MaxMinutes")) >= cnsMaxLimitMinutes Then
ArgMinutesLimit= cnsMaxLimitMinutes
End IF
End IF
'最大ファイル数制限 初期値500000
IF IsEmpty(objNamed) =vbFalse And ObjNamed.Exists("MaxFilesCount") And objNamed.Item("MaxFilesCount") <> "" Then
IF ArgFilesLimite >= CLng(objNamed.Item("MaxFilesCount")) Then 
ArgFilesLimite= cnsLimitTime
ElseIF CLng(objNamed.Item("MaxFilesCount")) >= cnsMaxFilesLimit Then
ArgFilesLimite= cnsMaxFilesLimit
End IF
End IF
On Error Goto 0

Wscript.Echo str : Wscript.Echo Cbool(IsEmpty(objNamed)) : Wscript.Echo vbTrue
FindFolder(Fso.Getfolder(str))

'// 結果報告
If blResult = False Then
DT2=Now
Wscript.Echo Cnt & "Files" & vbcrlf & "Time: " & cDate(DT2-DT) & vbCrlf & "End"
Else
Wscript.Echo "CNT:" & CNT & Vbcrlf & minute(DT2-DT) & "Count or TimeOver End"
End IF

'// 後処理
Ts.Close
Set Ts = Nothing
'FSO.Deletefolder(testFolder)
Set FSO = Nothing
Set WSH = Nothing



'// Sub Prosedure

Sub FindFolder(ByVal objMainFolder)
  Dim objSubFolder
  Dim objFile
  Dim copyFile
'// フォルダがあれば再帰
Wscript.Echo "Line:0100 " & objMainFolder.Path & FSO.GetFolder(objMainFolder.Path).Attributes
For Each objSubFolder In objMainFolder.SubFolders
IF FSO.GetFolder(objSubFolder).Attributes <> 22 Then
FindFolder objSubFolder
End IF
Next

'// フォルダの中のファイル情報を表示  : 日時 サイズ ファイル名 フォルダパス
For Each objFile In objMainFolder.files
On Error Resume Next
IF IsEmpty(objNamed) =vbFalse And ObjNamed.Exists("Ext") And objNamed.Item("Ext") <> "" Then
If FSO.GetExtensionName(objFile) = objNamed.Item("Ext") Then
' --------------------------------------
Ts.WriteLine fnAddDBQuotes(objFile.Name) & vbTab & objFIle.DateCreated & vbTab & objFile.DateLastModified & vbTab _
& objFile.Size & vbTab & objFile.Attributes & vbTab & fnAddDBQuotes(FSO.GetExtensionName(objFIle)) & vbTab & fnAddDBQuotes(objFile.Type) & vbTab _
& fnAddDBQuotes(objFIle.ShortName) & vbTab & fnAddDBQuotes(objFile.ParentFolder) & vbTab & fnAddDBQuotes(objFIle.ShortPath)
  If Cnt=ArgFilesLimite Then
  blResult = True
  Exit Sub
  Else
  CNT = CNT + 1
  DT2 = Now
  End IF
  If Minute(DT2-DT) >=ArgMinutesLimit Then blResult = True : Exit sub
' --------------------------------------
End IF
ELSE
' --------------------------------------
Ts.WriteLine fnAddDBQuotes(objFile.Name) & vbTab & objFIle.DateCreated & vbTab & objFile.DateLastModified & vbTab _
& objFile.Size & vbTab & objFile.Attributes & vbTab & fnAddDBQuotes(FSO.GetExtensionName(objFIle)) & vbTab & fnAddDBQuotes(objFile.Type) & vbTab _
& fnAddDBQuotes(objFIle.ShortName) & vbTab & fnAddDBQuotes(objFile.ParentFolder) & vbTab & fnAddDBQuotes(objFIle.ShortPath)
  If Cnt=ArgFilesLimite Then
  blResult = True
  Exit Sub
  Else
  CNT = CNT + 1
  DT2 = Now
  End IF
  If Minute(DT2-DT) >=ArgMinutesLimit Then blResult = True : Exit sub
' --------------------------------------
End iF
Next
End Sub

Function fnAddDBQuotes(str)
fnAddDBQuotes = Chr(34) & cStr(str) & Chr(34)
End Function

これはVBScriptでファイル一覧作成と同じでCMD.exeでカレントフォルダを開きCscript.exe "%USERPROFILE%\Documents\CscriptCurrentDirFileListUTF16LEN.vbs /Ext:pdf /MaxMinutes:60 /MaxFilesCount:20000
とすると名前付き引数によってPDFのみ出力します。出力先はtsvfilefolderです。
なお
``Cscript.exe "%USERPROFILE%\Documents\CscriptCurrentDirFileListUTF16LEN.vbs`でも動きます。このときは拡張子の制限がありません。
元のVBSCRIPTはルートフォルダをカレントにするとシステム領域を踏んでエラーが起きます。しかしこれはそれを回避しました。
拡張子はTSVです。
これをExcelで読み込むときは拡張子をcsvに変えるかTSVファイルを関連付けしてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?