SimonKravis
SimonKravis

Reputation: 659

How can I programmatically rename a Windows folder containing illegal characters?

I would like to programmatically rename a Windows folder containing one or more illegal Windows characters using VBA. (The folder tree comes from a Mac/Linux environment).

The illegal character shows as a . in Windows/File Explorer, which can manipulate the folder OK.

Methods I have tried unsuccessfully include using the FileSystem Object and the VBA Name command.

Getting the actual name of the folder with the illegal char is the problem.

Doing dir /X shows the short (8.3 format) name of the folder but the full name appears in the command window with ? replacing the illegal char.

Supplying this name with the ? to various routines for folder operations (e.g. FileSystemObject GetFolder, VB Name function, GetShortName) results in the operation not finding the file to operate on.

Running Dir /X > Foldernames.txt produces an ASCII file which shows a ? replacing the illegal char, but examining the file in a binary editor (Frhed) shows 3 bytes for the illegal character in the full folder name. These are Chr(239), Chr(128) and Chr(162). Using this string to replace the illegal char the folder name still results in folder not found behaviour.

Using the actual illegal value (Chr (149))in the folder name also results in folder not found behaviour.

A short file name (8.3 format ) is shown in the Dir /X output and the folder can be accessed via this name. However, I can't see how to distinguish between short names for folders with different illegal chars in the same position, and shortname generation only occurs when the folder exists, so unless I can access the foldername with the illegal char directly it's not much help.

There is a unicode symbol for a placeholder (UxFFFD) which shows as a question mark in a black diamond which I have seen occasionally but not in in any Dir /X listings.

Upvotes: 0

Views: 532

Answers (2)

SimonKravis
SimonKravis

Reputation: 659

I have found a very laborious way of accessing files and folders with illegal characters in them via their short (8.3) format names. Generating a short name from a path which does not exist is not possible - as the algorithm for generating short names is apparently subject to change and I could not find a reverse-engineer of it.

The only way to get the short name is to do a Dir /X listing for the folder with illegal char or containing a file name with an illegal char and send it to file, which can then be parsed. The long name of the file or folder in the file sometimes includes the illegal character (if it is a ?, which is commonest) so that can be searched for. VBA code for dealing with folders is below. Once the short name of the folder with the illegal char is found it can be easily renamed and returned as a ByRef parameter.

' Procedure : LegalPath
' Author    : Simon
' Date      : 11/12/2017
' Purpose   : returns true if all path chars are legal and changes illegals to _ in sLegalPath if not

Public Function LegalPath(ByVal sPath As String, ByRef sLegalPath As String)            As Boolean

Dim iColon As Long
Dim J As Long
Dim sIllegalChars As String
Dim sOutPath As String
On Error GoTo LegalPath_Error

LegalPath = False
sIllegalChars = ""
'If InStr(sPath, "\") <> 0 Then Exit Function
If InStr(sPath, "/") <> 0 Then sIllegalChars = sIllegalChars + "/"

iColon = InStr(sPath, ":")    ' allow colon at loc 2
If iColon <> 0 And iColon <> 2 Then sIllegalChars = sIllegalChars + ":"
If InStr(sPath, "*") <> 0 Then sIllegalChars = sIllegalChars + "*"
If InStr(sPath, "?") <> 0 Then sIllegalChars = sIllegalChars + "?"
If InStr(sPath, "<") <> 0 Then sIllegalChars = sIllegalChars + "<"
If InStr(sPath, ">") <> 0 Then sIllegalChars = sIllegalChars + ">"
If InStr(sPath, "|") <> 0 Then sIllegalChars = sIllegalChars + "|"

' check for bullet code (149)
For J = 1 To Len(sPath)
    If (asc(Mid(sPath, J, 1)) = 149) Then
        sIllegalChars = sIllegalChars & Mid(sPath, J, 1)
    End If
Next J

If (sIllegalChars <> "") Then
    LegalPath = False
    ' replace with illegals with underscore
    sOutPath = sLegalPath
    For J = 1 To Len(sIllegalChars)
        sOutPath = Replace(sOutPath, Mid(sIllegalChars, J, 1), "_")
    Next J
    sLegalPath = sOutPath
    Dim sParentFolder As String
    sParentFolder = GetFolderFromPath(TruncateR(sPath))
    Call shell(GetDAFolder & "\ListDir.bat """ & sParentFolder & """ """ & GetDAFolder & "\ListDir.txt""")

    Dim a As TextStream
    Dim fs As New Scripting.FileSystemObject
    Set a = fs.OpenTextFile(GetDAFolder & "\ListDir.txt", ForReading, False)


    Dim sWindowsFolderName As String
    Dim sWindowsShortName As String
    Dim sLine As String
    sWindowsFolderName = GetFileFromPath(TruncateR(sPath))
    Do While a.AtEndOfStream <> True
        sLine = a.ReadLine
        If (Len(sLine) > 50) Then
            If (Mid(sLine, 50) = sWindowsFolderName) Then
                sWindowsShortName = Mid(sLine, 37, 8)
                Name sParentFolder & "\" & sWindowsShortName As sLegalPath
                Exit Function
            End If
        End If
    Loop

Else
    LegalPath = True

End If

End Function

For files with illegal names, the approach is very similar. Illegal chars are replaced by _. Note that Unicode characters are not flagged as illegal.

Public Function IsIllegalFileCharIN(ByRef sFileName As String, ByVal sFolder As String) As Boolean

Dim sRegex As String
Dim objRegExp As New RegExp
Dim sOut As String

sRegex = "[<>:""/\\|?*„]+"

With objRegExp
    .Pattern = sRegex
    .IgnoreCase = True
    .Global = True
    IsIllegalFileCharIN = .test(sFileName)

End With


If (IsIllegalFileCharIN) Then

    Dim sLegalFileName As String
    With objRegExp
        .Pattern = sRegex
        .IgnoreCase = True
        .Global = True
        sLegalFileName = .Replace(sFileName, "_")
    End With

    ' find file short name


    Call shell(GetDAFolder & "\ListDir.bat """ & sFolder & """ """ & GetDAFolder & "\ListDir.txt""")

    Dim a As TextStream
    Dim fs As New Scripting.FileSystemObject
    Set a = fs.OpenTextFile(GetDAFolder & "\ListDir.txt", ForReading, False)

    Dim sWindowsFolderName As String
    Dim sWindowsShortName As String
    Dim sLine As String
    sWindowsFolderName = sFileName
    Do While a.AtEndOfStream <> True
        sLine = a.ReadLine
        If (Len(sLine) > 50) Then
            If (Mid(sLine, 50) = sWindowsFolderName) Then
                sWindowsShortName = Mid(sLine, 37, 12)
                Name sFolder & "\" & sWindowsShortName As sFolder & "\" & sLegalFileName
                sFileName = sLegalFileName
                Exit Function
            End If
        End If
    Loop

End If



On Error GoTo 0
End Function

GetDAFolder is a dedicated folder. The batch file ListDir.Bat contains dir /X %1 >%2

Upvotes: 0

Kajkrow
Kajkrow

Reputation: 304

I suggest doing this via a batch-job.

Get the actual name of the file via a list.

You could use a batch like this:

dir "F:\batchs" > "F:\batchs\list.txt"
exit

If you found out the name copy it and replace "'inserthere'" in this code:

ren '_inserthere_' newname.txt
exit

and then run this as a batch job again. This might do the job.

Upvotes: 0

Related Questions