Windows에서 파일 이름 인코딩 결정 및 변경


1

Windows 서버에 이름에 특정 악센트 문자가있는 파일이 있습니다. Windows 탐색기에서 파일이 정상적으로 표시되지만 기본 설정으로 명령 프롬프트에서 'dir'을 실행하면 대체 문자가 표시됩니다.

예를 들어, 문자 ö가 o"목록 과 같이 표시됩니다 . 인코딩 / 코드 페이지가 충돌하여 SMB를 통해 다른 플랫폼에서 이러한 파일에 액세스 할 때 문제가 발생합니다. 모든 파일에 문제가있는 것은 아니며 문제 파일의 출처를 모릅니다.

예:

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

파일 및 디렉토리 이름을 변경했지만 아이디어를 얻을 수 있습니다.

어떻게 이런 식으로 이름을 얻었는지 알 수 있습니까? 다른 플랫폼이나 도구를 사용하여 복사하거나 만들었습니까?

모든 문제 파일을 배치하고 이름을 바꾸려면 어떻게해야합니까? GUI 이름 바꾸기 유틸리티 몇 가지를 살펴 봤지만 문제가 표시되지 않고 Windows 탐색기에 표시된 이름으로 만 작동합니다.

드라이브의 파일 시스템이 ReFS인데, 이와 관련이있을 수 있습니까?

편집 : 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

관련 부분 만 보이도록 정리했습니다.

실제로 combining diaeresis세로 따옴표가 아닌 것처럼 보입니다 . 내가 이해하는 것처럼 유니 코드 정규화에 대해 이야기 할 때와 마찬가지로.


사용 chcp에 cmd적절한 코드 페이지를 설정하는 쉘. chcp- 활성 콘솔 코드 페이지 변경을 참조하십시오 . 기본 코드 페이지는 Windows 로캘에 의해 결정됩니다.
— DavidPostill

nixer하십시오 편집 질문을하고 추가 실제 등의 예를 dir( Copy & Paste의 cmd창). @DavidPostill chcp은 충분하지 않습니다. 문자 ( 라틴어 소문자 O와 Diaeresis ) 대신 정식 또는 호환성 분해 o ̈ ( U+006F 라틴 문자 소문자 O 다음에 U+0308 Diaeresis 결합 ) 가 표시되는 것 같습니다 . öU+00F6
— JosefZ

@DavidPostill @JosefZ 함께 놀았 chcp지만 이름이 올바르게 표시되지 않았습니다. 그냥와 "같은 다른 문자로 변경합니다 ?. 따라서 원래 분해되어 저장된 것으로 보이며 명령 프롬프트에 실제 이름이 표시되고 Windows 탐색기는이를 즉시 다시 결합합니다.
— nixer

"이 문자가 파일 이름 , 경로 및 네임 스페이스 기사에 의해 예약되어 있기 때문에 파일 이름에 (인용 부호) 가 있다고 믿을 수 없습니다 . 파일 시스템 NTFS과 ReFS파일 시스템 모두에 적용해야 합니다. oneliner 실행하십시오 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]}}대신 dir하고 편집 다시 Copy&Paste에만 해당 출력 라인 (숫자는 충분합니다). 참고 "코드는 34 입니다.
— JosefZ

답변:


1

다음 간단한 Powershell 스크립트를 사용하여 문제를 재현 할 수 있습니다

$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:\test\1097217Rated$RatedName.txt" -Encoding utf8
$FormDName | Out-File "D:\test\1097217FormD$FormDName.txt" -Encoding utf8
$FormCName | Out-File "D:\test\1097217FormC$FormCName.txt" -Encoding utf8


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

위의 스크립트는 다음과 같이 업데이트 됩니다. 1st 는 구성 / 분해 된 유니 코드 문자, 즉 해당 유니 코드 이름에 대한 추가 정보를 표시합니다 ( Get-CharInfo 모듈 참조 ). 두 번째 로 가능한 솔루션의 초안 이 포함되어 있습니다.
출력 에서 cmd프롬프트 :

==> powershell -c D:\PShell\SU\1097217.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:\test\1097217FormCšöü.txt
What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
FormDšöü.txt Destination: D:\test\1097217FormDšöü.txt".
       : file name is already normalized D:\test\1097217Ratedšöü.txt

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

실제로 위의 dir출력 은 창과 같 1097217FormDsˇo¨u¨.txt으며 cmd유니 코드 인식 브라우저 는 위에 나열된 문자열 을 작성 하지만 유니 코드 분석기 는 최신 이미지뿐만 아니라 문자를 실제로 표시합니다.

악센트 결합

그러나 다음 예제는 전체 너비에서 문제를 보여줍니다. for루프가 악센트를 결합 하여 일반적인 악센트로 변경 합니다.

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

==>

가능한 해결책에 대한 매우 예술적인 초안 이 있습니다 (위 출력 참조).

""                                 # very artless draft of possible solution
Get-ChildItem "D:\test\1097217*" | 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 : Rename-Item필요한 경우에만 호출 ) :

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

그리고 그 출력 (다시, 여기에 구성된 문자열 로 렌더링 되며 아래 이미지는 cmd바이어스되지 않은 창 모양을 보여줍니다 ) :

What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
FormCšöü.txt Destination: D:\test\1097217FormCšöü.txt".
What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
FormDšöü.txt Destination: D:\test\1097217FormDšöü.txt".
What if: Performing the operation "Rename File" on target "Item: D:\test\1097217
Ratedšöü.txt Destination: D:\test\1097217Ratedšöü.txt".

악센트 결합

업데이트 된 cmd출력

업데이트 된 cmd 출력


아주 좋은 형사 일! 현재 PowerShell 스크립트는 문제를 해결하기위한 최상의 옵션 인 것 같습니다. 분해 된 유니 코드를 이해하는 파일 이름 바꾸기 유틸리티를 찾지 못했습니다.
— nixer

@nixer 업데이트 된 답변 참고 : 부분 이름을 바꾸면 도움이 될 수 있습니다!
— JosefZ

초안 스크립트는 현재 디렉토리에서 훌륭하게 작동합니다. 재귀 적으로 이름을 바꾸도록 수정하려고했지만 PowerShell 기술이 좋지 않아 아직 할 수 없었습니다.
— nixer

@nixer는 추가 요청에 대해 stackoverflow를 검색하십시오.
— JosefZ

0

지역 제어판 의이 탭에서 문제가 발생합니다 .

여기에 이미지 설명을 입력하십시오

이것은 화면 글꼴뿐만 아니라 파일 시스템 (기본적으로 설명하는 방식)에도 영향을줍니다.

스크린 샷은 내 컴퓨터에서 가져온 것입니다. 로케일을 영어로 변경하면 ľôščťž 파일 이름 과 같은 모든 특수 슬로바키아어 국가 문자 가 쓰레기가되고 일부는 해결 방법없이 파일을 열지 못하게합니다 (코드 페이지가 되돌릴 때까지). . 그러나이 문제는 áíé여러 언어에서 볼 수있는 보다 일반적인 자국 문자로는 나타나지 않습니다 .

이는 다른 로케일로 작성된 백업을 열려고하는 등 일부 오프라인 매체에도 영향을줍니다.

가장 쉬운 해결책은 리소스에 액세스하는 모든 컴퓨터에서 동일한 로캘을 유지하는 것입니다.

해결 방법은 다른 로케일을 가진 시스템을 판별하고 해당 시스템과 모든 파일 이름에서 모든 국가 문자 (예 : č-> c, ž-> z) 의 대량 교체를 수행하는 시스템을 판별하는 것입니다 . Total Commander (파일 관리자)는 전체 디렉토리 트리에서 이러한 각 쌍을 한 번에 교체 할 수 있습니다. 그런 다음 해당 머신을 영어로 되돌 리거나 (자체 백업을 읽지 못할 수도 있음) 사용자가 파일 이름에 자국 문자를 사용하지 않도록 요청하여 그대로 유지할 수 있습니다.

(하지만 그 전에 한 가지 시도를 할 수 있습니다. chcp다른 로케일로 시스템에서 실행 하고, 사용중인 코드 페이지 (예 : 852)를 학습 한 다음로 다른 시스템에서 시도해보십시오 chcp 852. 문제가 만족스럽게 해결되는지 여부는 확실하지 않습니다.)


팁 고마워. 여러 로케일을 시도했지만 그중 어느 것도 분해에 영향을 미치지 않았으며 문제를 재현 할 수 없었습니다. 또한 몇 가지 파일 이름 바꾸기 유틸리티를 사용해 보았지만 분해로 작동하는 방법을 알지 못했습니다. 이로 인해 파일이 엉망이 된 도구를 사용하여 다른 컴퓨터 또는 플랫폼에서 파일이 전송되었다고 믿게되었습니다. 나는 여전히이 문제가있는 모든 파일을 찾아서 수정할 수있는 대량 이름 바꾸기를 찾고 있습니다.
— nixer

@nixer – 벌크 이름 변경과 관련하여 이미 수행 방법을 썼습니다. 자세한 내용 : TCMD 내에서 다중 이름 변경 도구 (주 메뉴에서 액세스 가능)의 검색 및 바꾸기를 사용하십시오. 이전에 조심해서 백업을 생성하더라도 잘못된 이름 변경 순서를 사용하여 논리적으로 파악할 수 있습니다. 최선의 선택 (가능한 경우)은 파일을 사용하여 파일을 업로드 한 사람을 결정하고 해당 사용자의 컴퓨터에 집중하는 것입니다.
— miroxlav

0

JosefZ의 스크립트를 기반으로 다음은 재귀 적으로 작동하는 수정 된 버전입니다.

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"
    }
}

-WhatIf테스트 후 제거하십시오 . 너무 길었던 경로에 문제가 있었지만 다른 게시물의 주제입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.