- ベストアンサー
VBAで読めないファイル名(文字列)
ネットから入手したファイル名がVBAで読めずエラーが出ることがあります。 読めない文字列は、OS(Windows)のファイル名としては認識はされていて開くことは出来ます。 ファイルEditorで表示される認識されない文字列の例 : https://www.youtube.com/watch?v=LDE7x1SPYmE&list=PLs2VObp8WiuYOLmN8TMGILWptsJaeiSaU&index=17 テキストEditorでコピペすると J̲e̲thro T̲ull - H̲e̲avy H̲o̲rses そもそもJ_はどんな文字なのでしょうか ? 最終的には、普通に読めるような型式にコンバートしたい。
- みんなの回答 (11)
- 専門家の回答
質問者が選んだベストアンサー
> ローカルウインドウで?として見える文字列は全て処理対象になると言うわけですよね? はい、元が何であれ?で表示されたものは対象になると思います。 ただし、元々?だったものも対象になりますので、Asc()で?に変換されるものと表示上の理由で?にされたものだけを対象にするには If Asc(Mid(fileName, ii, 1)) <> 63 Or Mid(fileName, ii, 1) = "?" Then のようにしておく必要があります。 以前にも回答しましたがファイル名には?は使えないので今回はAsc()で?に変換されるものだけを考えています。
その他の回答 (10)
- kkkkkm
- ベストアンサー率66% (1719/2589)
objFSO.MoveFile folderPath & .Name, folderPath & newfilename の所をやめて Call CropAndSaveImageByWIA(folderPath ,objFile) に変更して CropAndSaveImageByWIAの folderPath & fileName で受けてるところを CropAndSaveImageByWIA(ByVal folderPath As String, ByRef objFile As Object) としてその時に処理したら(中身もファイル名の所は変更しなくてはいけないと思いますが) 実際のファイル名を変更しなくても行けたかもしれないような気もします。 ただ、今回のようにファイル名を変更したほうがあとあとアクセスするときに簡単でいいとは思います。 とりあえず、なんかそんな気もするなという事でこれは蛇足な独り言と思ってください。
お礼
個人的には、ファイル名を変更したほうが考え方として後の処理の順番的にもスッキリするので 先のコードを採用したいと思います。 最後に確認ですが ASCで63である文字(?)であれば、?をターゲットの文字列から削除して行く処理なので ローカルウインドウで?として見える文字列は全て処理対象になると言うわけですよね?
- kkkkkm
- ベストアンサー率66% (1719/2589)
> newfilename = Replace(fileName, "?", "_") これ私もやりました。Replace(fileName, "?", "")ですが、GetOpenFilenameで取得したfileNameでは駄目だったんですよ・・・ fileNameの中では?じゃなかったのです。で、一文字ずつのループにしました。 Dirで取得したものは?に変わっていると思いますので変更されると思います。 移動のエラーは新規ファイル名の問題ではなく元のファイル名が正しくない(Dirで?に変わっている)のが理由だと思います。
- kkkkkm
- ベストアンサー率66% (1719/2589)
> 何か?正攻法的な解決方法はありませんか? fileNameを変数ではなくオブジェクトとしてやらないと移動などでは駄目みたいですので冗長かもしれませんが Sub Test() Dim objFSO As FileSystemObject Dim objFolder As Folder Dim objFile As File Dim strDir As String Dim i As Long Dim fd As FileDialog Set fd = Application.FileDialog(msoFileDialogFolderPicker) With fd .InitialFileName = "C:\Ok\" 'Users\TAC_\download" .Title = "フォルダを選択してください" .AllowMultiSelect = False If .Show = -1 Then MsgBox "選択されたフォルダ: " & vbCrLf & _ .SelectedItems(1) Else MsgBox "キャンセルされました。" End If End With ' トリミングしたいフォルダのフルパスを取得 Dim folderPath As String folderPath = fd.SelectedItems(1) & "\" strDir = fd.SelectedItems(1) '"フォルダをフルパスで指定" Set objFSO = New FileSystemObject If Not objFSO.FolderExists(strDir) Then MsgBox ("指定のフォルダは存在しません") Exit Sub End If Set objFolder = objFSO.GetFolder(strDir) For Each objFile In objFolder.Files With objFile If objFSO.GetExtensionName(.Name) = "csv" Then Dim ii As Long Dim newfilename As String For ii = 1 To Len(.Name) If Asc(Mid(.Name, ii, 1)) <> 63 Then newfilename = newfilename & Mid(.Name, ii, 1) End If Next objFSO.MoveFile folderPath & .Name, folderPath & newfilename End If End With Next Set objFSO = Nothing Set objFolder = Nothing End Sub
お礼
教えていただいたコードをお借りして処理してみました。 問題だった?が外れてうまく処理できました。 これで少し処理数を増やして試用をしたいと思います。 Option Explicit Sub test2() 'FileSystemObject (実行時バインディング) Dim objFSO As Object Set objFSO = CreateObject("Scripting.FileSystemObject") Dim fd As FileDialog Set fd = Application.FileDialog(msoFileDialogFolderPicker) With fd .InitialFileName = "Users\TAC_\download" .Title = "フォルダを選択してください" .AllowMultiSelect = False If .Show = -1 Then MsgBox "選択されたフォルダ: " & vbCrLf & _ .SelectedItems(1) Else MsgBox "キャンセルされました。" End If End With ' トリミングしたいフォルダのフルパスを取得 Dim folderPath As String folderPath = fd.SelectedItems(1) & "\" Dim strDir As String strDir = fd.SelectedItems(1) '"フォルダをフルパスで指定" If Not objFSO.FolderExists(strDir) Then MsgBox ("指定のフォルダは存在しません") Exit Sub End If Dim objFolder As Object Set objFolder = objFSO.GetFolder(strDir) Dim objFile For Each objFile In objFolder.Files With objFile If objFSO.GetExtensionName(.Name) = "jpg" Then Dim ii As Long Dim newfilename As String For ii = 1 To Len(.Name) If Asc(Mid(.Name, ii, 1)) <> 63 Then newfilename = newfilename & Mid(.Name, ii, 1) End If Next objFSO.MoveFile folderPath & .Name, folderPath & newfilename End If End With Next ' ディレクトリ内のファイルを改めて処理 Dim fileName As String fileName = Dir(folderPath & "*.jpg") Do While fileName <> "" Call CropAndSaveImageByWIA(folderPath & fileName) ' 次のファイルを処理 fileName = Dir Loop MsgBox "処理終了" Set objFSO = Nothing Set objFolder = Nothing Set fd = Nothing End Sub
- kkkkkm
- ベストアンサー率66% (1719/2589)
' 移動先にファイルがあれば削除 If objFSO.FileExists(folderPath & filename) Then objFSO.DeleteFile folderPath & filename End If これはもしかして元のファイルを削除してるのではないでしょうか
お礼
ありがとうございます。 >もしかしたら逆じゃないでしょうか。 おっしゃるとおり、ミスしました。 filenameをnewfilenameに変名するのですから objFSO.MoveFile folderPath & filename, folderPath & newfilename ですね。 >これはもしかして元のファイルを削除してるのではないでしょうか この処理も不用なので削除しました。 以上を踏まえてコードを訂正しましたが MoveFileでエラーが出ました。 実行エラー: パスが見つかりません。 思うにこのMoveを使う方法はだめなようです。 他のアプローチとして以下のURLを参考に https://www.togu.co.jp/column/detail/59 '名前の変更 objFSO.getfile(folderPath & filename).Copy folderPath & newfilename objFSO.getfile(folderPath & filename).Delete これも「ファイル名がみつかりません」とエラーがでました。 何か?正攻法的な解決方法はありませんか?
補足
以下も試してみましたが、Nameで「ファイル名がみつかりません」とエラーが出ます。 'ファイル名内の環境依存文字をアンダースコア(_)に置換 Dim fileName As String fileName = Dir(folderPath & "*.jpg") Dim newfilename As String Do While fileName <> "" newfilename = Replace(fileName, "?", "_") ' ハテナマークをアンダースコアに置換 Name folderPath & fileName As folderPath & newfilename fileName = Dir Loop
- kkkkkm
- ベストアンサー率66% (1719/2589)
> objFSO.MoveFile folderPath & newfilename, folderPath & filename FileSystemObject.MoveFile source, destination 引数sourceに指定したファイルを、引数destinationに移動します。 もしかしたら逆じゃないでしょうか。
- heisukewada
- ベストアンサー率58% (93/160)
うまく説明できませんが この文字列は、ストライクスルー(strikethrough)と呼ばれます。通常、テキストエディターやHTMLなどの文書形式で使用され、テキストを取り消したり、無効にするために使用されます。今回は、アンダーラインのように見えます。 テキストエディターやWebブラウザーなどのソフトウェアは、Unicodeのストライクスルー文字を適切に処理し、表示することができます。 UTF-8エンコーディングを使用してテキストを保存しても、ストライクスルーの効果を持つ文字は正しく表示されるはずですが、UTF-8自体がストライクスルーを、きちんとエンコードできることではありません。(アンダーラインではなく、アンダーバーのように見えます) J̲e̲thro T̲ull - H̲e̲avy H̲o̲rses (Full Album) 1978 を、メモ帳に貼り付けると J_e_thro T_ull - H_e_avy H_o_rses (Full Album) 1978 このように見えますが、 _ (アンダーバー)と、 ̲ ストライクスルー は、違います。
お礼
追加の回答ありがとうございます。 アンダーラインのように見える文字にも ストライクスルー(strikethrough)と言う呼び名が在ったのですね。 まだ、変名できずに色々と模索しています。 kkkkkmさんとの一連のスレの流れを見て 何かアドバイスできる事があればお願いします。
- kkkkkm
- ベストアンサー率66% (1719/2589)
> GetOpenFilenameではなくFileDialogで取得しても問題ないなら はい、問題ありませんでした。 説明が色々不足していたのですが ファイル名を fileName = "J?e?thro T?ull - H?e?avy H?o?rses (Full Album) 1978" と直接文字列として代入した場合は「?」がそのまま変数に入るので Mid(fileName, i, 1)と「?」を比較しても正しい結果が得られるのですが、ファイル名をFileDialogなどで取得した場合は「?」は変数には入っていないのでMid(fileName, i, 1)と「?」を比較した場合結果は正しくありません。 多分なのですが Asc(Mid(fileName, i, 1)) とすると対象の文字が範囲外の場合に「?」のコード「63」を返すのだと思います。 ファイル名に「?」が使えないので比較する文字列が実際の「?」かどうかは見ていません。 最初に > VBAでファイル名を変数に読み込むと文字化け部分のデータが「?」になりますから とやたら省略した説明をしたので勘違いさせてしまったと思います。
お礼
ありがとうございます。 現在使用中のコードに教えてもらったファイル名のチェック用コードを追加してみました。 なぜだか? Call CropAndSaveImageByWIA(folderPath & filename) でIMGを処理していますが、 昨日と同じくエラーが出ます。 エラーコードが今度は違って「指定されたファイルが見つかりません」となりました。 考えてみると?が無いファイル名はフォルダー内に存在しないので当然です。 そこで元のファイル名を?の無いファイル名に変名した後でCall処理する事にしました。 以下のようにコードを変更しましたが「名前の変更」が上手くいきません。 エラー : 無効なプロシージャの呼び出しまたは引数 どこが間違っているのでしょうか ? Option Explicit Sub 複数画像一括トリミング() 'フォルダ選択ダイアロFileDialogグ ---> トリミングしたいフォルダのフルパスを指定 Dim fd As FileDialog Set fd = Application.FileDialog(msoFileDialogFolderPicker) With fd .InitialFileName = "C:\Users\TAC_\download" .Title = "フォルダを選択してください" .AllowMultiSelect = False If .Show = -1 Then MsgBox "選択されたフォルダ: " & vbCrLf & _ .SelectedItems(1) Else MsgBox "キャンセルされました。" End If End With ' トリミングしたいフォルダのフルパスを取得 Dim folderPath As String folderPath = fd.SelectedItems(1) & "\" ' ディレクトリ内のファイルを処理 Dim filename As String filename = Dir(folderPath & "*.jpg") 'ファイル名に問題が無いか?チェック Dim ii As Long Dim newfilename As String For ii = 1 To Len(filename) If Asc(Mid(filename, ii, 1)) <> 63 Then newfilename = newfilename & Mid(filename, ii, 1) End If Next 'FileSystemObjectオブジェクト (実行時バインディング) Dim objFSO As Object Set objFSO = CreateObject("Scripting.FileSystemObject") ' 移動先にファイルがあれば削除 If objFSO.FileExists(folderPath & filename) Then objFSO.DeleteFile folderPath & filename End If '名前の変更 (NAMEでなくMOVEを使用) objFSO.MoveFile folderPath & newfilename, folderPath & filename Do While filename <> "" Call CropAndSaveImageByWIA(folderPath & filename) ' 次のファイルを処理 filename = Dir Loop MsgBox "処理終了" End Sub
- kkkkkm
- ベストアンサー率66% (1719/2589)
> エクセルはUnicodeに対応しているが、VBAはShift_JISになっているため、 > Shift_JISにない文字は、文字化けしてしまい入力できない。 多分そうだと思います。 テストのコードですが fileName = "J?e?thro T?ull - H?e?avy H?o?rses (Full Album) 1978" ではなくて fileName = Application.GetOpenFilename(FileFilter:="CSVファイル(*.csv),*.csv", _ Title:="CSVファイルの選択") If fileName = False Then Exit Sub End If で取得したfileName で確認したほうがいいと思います。テストをCSVでしたので種類の絞り込みはCSVになってますから本来の種類にしてください。
補足
kkkkkmさん、ありがとうございます。 「GetOpenFilenameで取得したfileName で確認したほうがいいと思います」 との事ですが、現在試用中のコードでファイル名を取得する方法として FileDialog(msoFileDialogFolderPicker)で読み込むフォルダーを指定し ファイル名は、以下のコードで指定しています folderPath = fd.SelectedItems(1) & "\" Dir(folderPath & "*.jpg") GetOpenFilenameではなくFileDialogで取得しても問題ないなら 教えてもらったコードを途中に挟んでファイル名をチェックしてエラーが出ないようにして 処理を始めたいと思います。 Sub test() Dim fileName As String Dim newfilename As String ' 元のファイル名を取得 'fileName = "J?e?thro T?ull - H?e?avy H?o?rses (Full Album) 1978" ChDir "C:\Users\****\download" fileName = Application.GetOpenFilename(FileFilter:="jpegファイル(*.jpg),*.jpg", _ Title:="画像ファイルの選択") If fileName = "" Then Exit Sub End If Dim i As Long For i = 1 To Len(fileName) If Asc(Mid(fileName, i, 1)) <> 63 Then newfilename = newfilename & Mid(fileName, i, 1) End If Next MsgBox newfilename End Sub
- heisukewada
- ベストアンサー率58% (93/160)
適当で申し訳ないですが Sub RemoveStrikethroughFromFileName() Dim fileName As String Dim modifiedFileName As String ' 元のファイル名を取得 fileName = "J̲e̲thro T̲ull - H̲e̲avy H̲o̲rses (Full Album) 1978" ' ストライクスルーを削除して修正されたファイル名を生成 modifiedFileName = RemoveStrikethrough(fileName) ' 修正されたファイル名を出力 MsgBox modifiedFileName End Sub Function RemoveStrikethrough(ByVal text As String) As String Dim i As Integer Dim result As String ' 文字列内のストライクスルーを削除 For i = 1 To Len(text) If Mid(text, i, 1) <> "̲" Then result = result & Mid(text, i, 1) End If Next i RemoveStrikethrough = result End Function
お礼
heisukewadaさん、参加いただきありがとうございます。 昨日のコードを検証中、今回の読めない文字列を含むファイルがあると 「パラメーターが間違っています。」とエラーが出ました。 https://okwave.jp/qa/q10256062.html 頂いたコードで上手く処理できてコンバート出来ました。 VBAで処理出来ない文字列とは、以下のような定義となるのでしょうか ? UnicodeにあってShift_JISにない文字は、「?」と表示される。 エクセルはUnicodeに対応しているが、VBAはShift_JISになっているため、 Shift_JISにない文字は、文字化けしてしまい入力できない。
- kkkkkm
- ベストアンサー率66% (1719/2589)
VBAでファイル名を変数に読み込むと文字化け部分のデータが「?」になりますから For i = 1 To Len(FileName) If Asc(Mid(FileName, i, 1)) <> 63 Then NewFileName = NewFileName & Mid(FileName, i, 1) End If Next で、「?」を削除してみてはいかがでしょう。
お礼
kkkkmさん、毎回参加いただきありがとうございます。 昨日のコードを検証中、今回の読めないファイルがあると同じく 「パラメーターが間違っています。」とエラーが出ました。 頂いたコードで上手く処理できてコンバート出来ました。 VBAで処理出来ない文字列とは、以下のような定義となるのでしょうか ? UnicodeにあってShift_JISにない文字は、「?」と表示される。 エクセルはUnicodeに対応しているが、VBAはShift_JISになっているため、 Shift_JISにない文字は、文字化けしてしまい入力できない。 Option Explicit Sub test() Dim fileName As String Dim newfilename As String ' 元のファイル名を取得 fileName = "J?e?thro T?ull - H?e?avy H?o?rses (Full Album) 1978" Dim i As Long For i = 1 To Len(fileName) If Asc(Mid(fileName, i, 1)) <> 63 Then newfilename = newfilename & Mid(fileName, i, 1) End If Next MsgBox newfilename End Sub
お礼
確認の為の回答、ありがとうございます。 これで安心しました。 最後までお付き合いいただき感謝いたします。