Determina e altera a codificação de nome de arquivo no Windows

1

Eu tenho arquivos em um servidor Windows que possuem certos caracteres acentuados no nome. Nos arquivos do Windows Explorer são exibidos normalmente, mas executando 'dir' no prompt de comando com configurações padrão exibe caracteres substituídos.

Por exemplo, o caractere ö é exibido como o" na listagem. Isso causa problemas ao acessar esses arquivos de outras plataformas em SMB, presumivelmente devido a páginas de código / codificação conflitantes. O problema não está presente em todos os arquivos e não sei de onde vieram os arquivos com problemas.

Exemplo:

E:\folder\files>dir
 Volume in drive E is data
 Volume Serial Number is 5841-C30E

 Directory of E:\folder\files  

07/05/2016  07:46 PM    <DIR>          .
07/05/2016  07:46 PM    <DIR>          ..
12/01/2015  11:12 AM            14,105 file with o" character.xlsx
01/22/2015  05:30 PM            11,598 file with correct ö character.xlsx
               2 File(s)         25,703 bytes
               2 Dir(s)  2,727,491,600,384 bytes free

Eu alterei nomes de arquivos e diretórios, mas você terá a ideia.

Alguma idéia de como os nomes poderiam ter sido assim? Talvez eles tenham sido copiados ou criados usando outra plataforma ou ferramenta?

Como posso encontrar e renomear todos os arquivos com problemas? Eu olhei para um par de utilitários de renomeação GUI, mas eles não vêem o problema e só funcionam com o nome mostrado no Windows Explorer.

Sistema de arquivos na unidade é ReFS, isso pode ter algo a ver com isso?

Editar: execute o comando do PowerShell

Y:\test>powershell -c Get-ChildItem ^|ForEach-Object {$x=$_.Name; For ($i=0;$i
-lt $x.Length; $i++) {\"{0} {1} {2}\" -f $x,$x[$i],[int]$x[$i]}}
file with o¨ character.xlsx o 111
file with o¨ character.xlsx ¨ 776

Limpo para mostrar apenas a parte relevante.

Parece que é realmente um combining diaeresis e não uma aspa vertical. Como deveria ser, como eu entendo, quando se fala de normalização unicode.

    
por nixer 05.07.2016 / 19:15

3 respostas

0

Baseado no script do JosefZ, aqui está uma versão modificada que funciona de forma recursiva:

Get-ChildItem "X:\" -Recurse | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    $file = $_.Fullname
    if ( $y.Length -ne $_.Name.Length ) {
        Rename-Item -LiteralPath "$file" -NewName "$y" -WhatIf
        Write-Host "renamed file $file"
    }
}

Remova -WhatIf após o teste. Eu tive problemas com caminhos que eram muito longos, mas esse é um tópico para outro post.

    
por 09.08.2016 / 14:47
1

Eu posso reproduzir seu problema usando o próximo script Powershell simples

$RatedName = "šöü"                            # set sample string
$FormDName = $RatedName.Normalize("FormD")    # its Canonical Decomposition
$FormCName = $FormDName.Normalize("FormC")    #     followed by Canonical Composition
                                              # list each string character by character
($RatedName,$FormDName,$FormCName) | ForEach-Object {
    $charArr = [char[]]$_ 
    "$_"      # display string in new line for better readability
              # display each character together with its Unicode codepoint
    For( $i=0; $i -lt $charArr.Count; $i++ ) { 
        $charInt = [int]$charArr[$i]
        # next "Try-Catch-Finally" code snippet adopted from my "Alt KeyCode Finder"
        #                                       http://superuser.com/a/1047961/376602
        Try {    
            # Get-CharInfo module downloadable from http://poshcode.org/5234
            #        to add it into the current session: use Import-Module cmdlet
            $charInt | Get-CharInfo |% {
                $ChUCode = $_.CodePoint
                $ChCtgry = $_.Category
                $ChDescr = $_.Description
            }
        }
        Catch {
            $ChUCode = "U+{0:x4}" -f $charInt
            if ( $charInt -le 0x1F -or ($charInt -ge 0x7F -and $charInt -le 0x9F)) 
                 { $ChCtgry = "Control" } else { $ChCtgry = "" }
            $ChDescr = ""
        }
        Finally { $ChOut = $charArr[$i] }
        "{0} {1,-2} {2} {3,5} {4}" -f $i, $charArr[$i], $ChUCode, $charInt, $ChDescr
    }
}
# create sample files
$RatedName | Out-File "D:\test97217Rated$RatedName.txt" -Encoding utf8
$FormDName | Out-File "D:\test97217FormD$FormDName.txt" -Encoding utf8
$FormCName | Out-File "D:\test97217FormC$FormCName.txt" -Encoding utf8


""                                 # very artless draft of possible solution
Get-ChildItem "D:\test97217*" | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    if ( $y.Length -ne $_.Name.Length ) {
        Rename-Item -NewName $y -LiteralPath $_ -WhatIf
    } else {
        "       : file name is already normalized $_"
    }
}

O script acima é atualizado da seguinte forma: mostra mais informações sobre caracteres Unicode compostos / decompostos, isto é, seus nomes Unicode (consulte Módulo Get-CharInfo ); rascunho muito de possível solução.
Saída do prompt cmd :

==> powershell -c D:\PShell\SU97217.ps1
šöü
0 š  U+0161   353 Latin Small Letter S With Caron
1 ö  U+00F6   246 Latin Small Letter O With Diaeresis
2 ü  U+00FC   252 Latin Small Letter U With Diaeresis
šöü
0 s  U+0073   115 Latin Small Letter S
1 ̌  U+030C   780 Combining Caron
2 o  U+006F   111 Latin Small Letter O
3 ̈  U+0308   776 Combining Diaeresis
4 u  U+0075   117 Latin Small Letter U
5 ̈  U+0308   776 Combining Diaeresis
šöü
0 š  U+0161   353 Latin Small Letter S With Caron
1 ö  U+00F6   246 Latin Small Letter O With Diaeresis
2 ü  U+00FC   252 Latin Small Letter U With Diaeresis

       : file name is already normalized D:\test97217FormCšöü.txt
What if: Performing the operation "Rename File" on target "Item: D:\test97217
FormDšöü.txt Destination: D:\test97217FormDšöü.txt".
       : file name is already normalized D:\test97217Ratedšöü.txt

==> dir /b D:\test97217*
1097217FormCšöü.txt
1097217FormDšöü.txt
1097217Ratedšöü.txt

De fato, acima de dir output parece como a janela 1097217FormDsˇo¨u¨.txt in cmd e meu navegador com reconhecimento de unicode compõe strings conforme listado acima, mas analisador unicode mostra os personagens verdadeiramente, assim como a imagem mais recente:

Noentanto,opróximoexemplomostraoproblemaemtodaasualargura:umloopformudacombinandoacentosparanormaluns:

==>for/F"delims=" %G in ('dir /b /S D:\test97217*') do @echo %~nxG & dir /B %~fG
1097217FormCšöü.txt
1097217FormCšöü.txt
1097217FormDsˇo¨u¨.txt
File Not Found
1097217Ratedšöü.txt
1097217Ratedšöü.txt

== >

Aqui está muito esboço sem arte de possível solução (veja o resultado acima):

""                                 # very artless draft of possible solution
Get-ChildItem "D:\test97217*" | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    if ( $y.Length -ne $_.Name.Length ) {
        Rename-Item -NewName $y -LiteralPath $_ -WhatIf
    } else {
        "       : file name is already normalized $_"
    }
}

( ToDo : invoque Rename-Item apenas se necessário):

Get-ChildItem "D:\test97217*" | ForEach-Object {
    $y = $_.Name.Normalize("FormC")
    if ($true) {                                         ### ToDo
        Rename-Item -NewName $y -LiteralPath $_ -WhatIf
    }
}

e sua saída (novamente, aqui estão strings compostas e a imagem abaixo mostra cmd window look unbiased) :

What if: Performing the operation "Rename File" on target "Item: D:\test97217
FormCšöü.txt Destination: D:\test97217FormCšöü.txt".
What if: Performing the operation "Rename File" on target "Item: D:\test97217
FormDšöü.txt Destination: D:\test97217FormDšöü.txt".
What if: Performing the operation "Rename File" on target "Item: D:\test97217
Ratedšöü.txt Destination: D:\test97217Ratedšöü.txt".

Atualizadocmdoutput

    
por 08.07.2016 / 01:12
0

O problema é originado nesta guia do painel de controle Região :

Isso afeta não apenas as fontes de tela, mas também o sistema de arquivos (basicamente da maneira que você descreve).

A captura de tela é da minha máquina. Se eu mudasse de local para inglês, todos os caracteres eslovacos especiais como ľôščťž em nomes de arquivos se tornariam um lixo, enquanto alguns deles impediriam completamente a abertura do arquivo (testado ...) com nenhuma solução alternativa (até que a página de código seja revertida). No entanto, esse problema não aparece com caracteres nacionais mais comuns, como áíé , que podem ser vistos em vários idiomas.

Isso também afeta algumas mídias off-line, por exemplo, na tentativa de abrir um backup feito com local diferente.

A solução mais fácil é manter a mesma localidade em todas as máquinas que acessam o recurso.

A solução alternativa é determinar qual máquina possui código de idioma diferente e que a máquina executa a substituição em massa de todos os caracteres nacionais (por exemplo, č - > c , ž - > z ) em todos os arquivos nomes. O Total Commander (um gerenciador de arquivos) pode realizar a substituição de cada par na árvore de diretórios inteira de uma só vez. Então você pode retornar essa máquina para o inglês (cuidado, pode não ser capaz de ler seus próprios backups), ou mantê-la como está, pedindo aos usuários para não usarem caracteres nacionais em nomes de arquivos.

(Ainda antes disso você pode tentar uma coisa: você pode executar chcp na máquina com essa localidade diferente, saber qual página de código está em uso (por exemplo, 852) e então tentar em outras máquinas com chcp 852 . se isso resolverá o problema satisfatoriamente.)

    
por 06.07.2016 / 11:14