[c#] C #에서 문자열 파일 경로를 안전하게 만드는 방법이 있습니까?

내 프로그램은 인터넷에서 임의의 문자열을 가져 와서 파일 이름으로 사용합니다. 이러한 문자열에서 잘못된 문자를 제거하는 간단한 방법이 있습니까? 아니면 이에 대한 사용자 지정 함수를 작성해야합니까?



답변

어, 사람들이 어떤 문자가 유효한지 추측하려고 할 때 싫어요. 완전히 이식 할 수없는 것 외에도 (항상 Mono에 대해 생각 함) 이전 주석 모두 25 개 이상의 유효하지 않은 문자를 놓쳤습니다.

'Clean just a filename
Dim filename As String = "salmnas dlajhdla kjha;dmas'lkasn"
For Each c In IO.Path.GetInvalidFileNameChars
    filename = filename.Replace(c, "")
Next

'See also IO.Path.GetInvalidPathChars


답변

유효하지 않은 문자를 제거하려면 :

static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();

// Builds a string out of valid chars
var validFilename = new string(filename.Where(ch => !invalidFileNameChars.Contains(ch)).ToArray());

유효하지 않은 문자를 바꾸려면 :

static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();

// Builds a string out of valid chars and an _ for invalid ones
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? '_' : ch).ToArray());

유효하지 않은 문자를 바꾸려면 (그리고 Hell * vs Hell $와 같은 잠재적 인 이름 충돌을 방지) :

static readonly IList<char> invalidFileNameChars = Path.GetInvalidFileNameChars();

// Builds a string out of valid chars and replaces invalid chars with a unique letter (Moves the Char into the letter range of unicode, starting at "A")
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? Convert.ToChar(invalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray());


답변

이 질문은 이전에 여러 요청되었으며 이전에 여러 지적했듯이 IO.Path.GetInvalidFileNameChars적절하지 않습니다.

첫째, PRN 및 CON과 같이 예약되어 있고 파일 이름에 허용되지 않는 이름이 많이 있습니다. 루트 폴더에만 허용되지 않는 다른 이름이 있습니다. 마침표로 끝나는 이름도 허용되지 않습니다.

둘째, 다양한 길이 제한이 있습니다. 여기 에서 NTFS에 대한 전체 목록을 읽어보십시오 .

셋째, 다른 제한이있는 파일 시스템에 연결할 수 있습니다. 예를 들어 ISO 9660 파일 이름은 “-“로 시작할 수 없지만 포함 할 수 있습니다.

넷째, 두 프로세스가 “임의로”같은 이름을 선택하면 어떻게합니까?

일반적으로 파일 이름에 대해 외부에서 생성 된 이름을 사용하는 것은 좋지 않습니다. 자신의 개인 파일 이름을 생성하고 사람이 읽을 수있는 이름을 내부적으로 저장하는 것이 좋습니다.


답변

나는 Grauenwolf에 동의하며 Path.GetInvalidFileNameChars()

내 C # 기여는 다음과 같습니다.

string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))";
Array.ForEach(Path.GetInvalidFileNameChars(),
      c => file = file.Replace(c.ToString(), String.Empty));

추신-이건 당연한 것보다 더 은밀합니다-저는 간결하게하려고했습니다.


답변

내 버전은 다음과 같습니다.

static string GetSafeFileName(string name, char replace = '_') {
  char[] invalids = Path.GetInvalidFileNameChars();
  return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray());
}

GetInvalidFileNameChars의 결과가 어떻게 계산되는지 잘 모르겠지만 “Get”은 그것이 사소하지 않다고 제안하므로 결과를 캐시합니다. 또한 이것은 잘못된 문자 집합을 반복하는 위의 솔루션과 같이 여러 번 대신 한 번만 입력 문자열을 탐색하여 소스 문자열에서 한 번에 하나씩 대체합니다. 또한 Where 기반 솔루션을 좋아하지만 유효하지 않은 문자를 제거하는 대신 대체하는 것을 선호합니다. 마지막으로, 문자열을 반복 할 때 문자를 문자열로 변환하지 않도록 정확히 한 문자를 대체합니다.

나는 프로파일 링을하지 않고 모든 것을 말한다. 이것은 나에게 단지 “느낌”이었다. 🙂


답변

지금 사용하고있는 함수는 다음과 같습니다 (C # 예제의 jcollum에게 감사드립니다).

public static string MakeSafeFilename(string filename, char replaceChar)
{
    foreach (char c in System.IO.Path.GetInvalidFileNameChars())
    {
        filename = filename.Replace(c, replaceChar);
    }
    return filename;
}

편의를 위해 “Helpers”클래스에 넣었습니다.


답변

파일 이름에 대해 사용자가 더 쉽게 읽을 수있는 모든 특수 문자를 신속하게 제거하려면 다음과 같이 잘 작동합니다.

string myCrazyName = "q`w^e!r@t#y$u%i^o&p*a(s)d_f-g+h=j{k}l|z:x\"c<v>b?n[m]q\\w;e'r,t.y/u";
string safeName = Regex.Replace(
    myCrazyName,
    "\W",  /*Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'*/
    "",
    RegexOptions.IgnoreCase);
// safeName == "qwertyuiopasd_fghjklzxcvbnmqwertyu"