.NET으로 특정 확장자를 가진 임시 파일을 어떻게 만들 수 있습니까?


277

확장명이 .csv 인 고유 한 임시 파일을 생성해야합니다.

내가 지금하는 일은

string filename = System.IO.Path.GetTempFileName().Replace(".tmp", ".csv");

그러나 이것이 내 .csv 파일이 고유하다는 것을 보장하지는 않습니다.

충돌 가능성이 매우 낮다는 것을 알고 있습니다 (특히 .tmp 파일을 삭제하지 않는다고 생각하면).이 코드는 나에게 좋지 않습니다.

물론 문제가되지 않아야하는 고유 한 파일을 찾을 때까지 임의의 파일 이름을 수동으로 생성 할 수 있지만 다른 사람들이이 문제를 처리 할 수있는 좋은 방법을 찾았는지 궁금합니다.


4
GetTempFileName에 대한주의 사항 GetTempFileName 메소드는 이전 임시 파일을 삭제하지 않고 65535 개 이상의 파일을 작성하는 데 사용되는 경우 IOException을 발생시킵니다. 사용 가능한 고유 임시 파일 이름이 없으면 GetTempFileName 메소드는 IOException을 발생시킵니다. 이 오류를 해결하려면 불필요한 모든 임시 파일을 삭제하십시오.
Max Hodges

2
임시 파일은 주로 특정 조건 세트에 사용됩니다. 파일 확장자가 중요한 경우 GetTempFileName을 사용하는 것이 쓰기 솔루션이 아닌지 궁금합니다. 오랜 시간이 걸렸다는 것을 알고 있지만 컨텍스트와 파일에 대해 더 자세히 알려 주면 더 나은 접근 방식을 제안 할 수 있습니다. 자세한 내용은 여기 : support.microsoft.com/kb/92635?wa=wsignin1.0
최대 스

1
명심가 GetTempFileName() 생성 새 파일 당신이 그것을 호출 할 때마다. -문자열을 즉시 다른 것으로 바꾸면 임시 디렉토리에 새로운 0 바이트 파일을 만들었습니다 (다른 사람들이 지적했듯이 65535 파일을 치면 결국 실패하게됩니다 ...)- -이를 피하려면 해당 폴더에 생성 한 파일 ( GetTempFileName()이상적으로는 finally 블록에 의해 반환 된 파일 포함)을 삭제해야합니다 .
BrainSlugs83

답변:


354

(통계적으로) 고유해야합니다.

string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv"; 

(위반 기사에서 충돌의 확률에 대해 인용하려면 :

... 운석에 부딪 힐 수있는 연간 위험은 170 억으로 한 번의 확률로 추정됩니다. 1 년에 수 조조의 UUID가 있으며 하나의 복제본이 있습니다. 다시 말해, 향후 100 년 동안 초당 10 억 개의 UUID를 생성 한 후에 만 ​​하나의 복제본을 생성 할 확률은 약 50 %입니다. 지구상의 모든 사람이 6 억 UUID를 소유하고 있다면 한 번의 복제 확률은 약 50 %입니다.

편집 : JaredPar의 의견도 참조하십시오.


29
그러나 쓰기 가능한 위치에 있다고 보장 할 수 없음
JaredPar

33
그리고 그것들은 통계적으로 거의 불가능할 정도로 독특하다고 보장 되지않습니다 .
paxdiablo 2012

30
@Pax : 두 개의 신기한 guid를 생성하는 것보다 1000 번 연속으로 복권에 당첨 될 확률이 높습니다. 그것은 내가 생각하기에 충분히 독특하다 ...
Mitch Wheat

11
@Mitch가 고유하지 않은 이유 는 동일한 경로에서 동일한 이름의 파일을 간단하게 만들 있기 때문 입니다. GUID는 독창적 인 것으로 보장되지만 예측 가능합니다. 즉, 귀하의 상자에서 생성 된 다음 guid 세트를 추측 할 수있는 충분한 정보가 제공됩니다
JaredPar

207
좋은 주 님, 구름에서 머리를 유지하기 위해 더 열심히 노력하십시오. 방법은 임의의 파일 이름을 생성 한 다음 존재하지 않는 경우 파일 이름을 생성하는 것입니다. 그냥 코드를 잘 작성하도록 도와주세요. 의사 난수 발생기와 보편적으로 고유 한 숫자에 대한이 모든 이야기는 완전히 불필요합니다.
Max Hodges

58

이 기능을 사용해보십시오 ...

public static string GetTempFilePathWithExtension(string extension) {
  var path = Path.GetTempPath();
  var fileName = Guid.NewGuid().ToString() + extension;
  return Path.Combine(path, fileName);
}

선택한 확장명으로 전체 경로를 반환합니다.

다른 사람이 기술적으로 해당 파일을 이미 만들었을 수 있으므로 고유 한 파일 이름을 생성 할 수는 없습니다. 그러나 누군가가 앱에서 생성 한 다음 guid를 추측하여 만들 가능성은 매우 낮습니다. 이것이 유일하다고 가정하는 것이 꽤 안전합니다.


4
아마도 Path.ChangeExtension는 () Guid.NewGuid ()보다 더 우아한 것 ToString () + 확장.
오핫 슈나이더

@ohadsc-사실, Guid.NewGuid().ToString() + extension심지어 정확하지도 않습니다Guid.NewGuid().ToString() + "." + extension
Stephen Swensen

4
나는 그것이 방법의 계약에 달려 있다고 생각 하지만 ( 예상 .txt하든이든 txt) ChangeExtension두 경우를
다룰

1
그것을 Extension 대신 Suffix라고 부르십시오. 모두가 행복하다고 생각합니다
Chiel ten Brinke

46
public static string GetTempFileName(string extension)
{
  int attempt = 0;
  while (true)
  {
    string fileName = Path.GetRandomFileName();
    fileName = Path.ChangeExtension(fileName, extension);
    fileName = Path.Combine(Path.GetTempPath(), fileName);

    try
    {
      using (new FileStream(fileName, FileMode.CreateNew)) { }
      return fileName;
    }
    catch (IOException ex)
    {
      if (++attempt == 10)
        throw new IOException("No unique temporary file name is available.", ex);
    }
  }
}

참고 : 이것은 Path.GetTempFileName과 같이 작동합니다. 파일 이름을 예약하기 위해 빈 파일이 작성됩니다. Path.GetRandomFileName ()에 의해 생성 된 충돌의 경우 10 회 시도합니다.


있다는 사실을 숙지 Path.GetRandomFileName()실제로는 디스크에 0 바이트 파일을 생성하고 해당 파일의 전체 경로를 반환합니다. 이 파일을 사용하지 않고 확장명을 변경하기 위해 이름 만 사용하십시오. 따라서 이러한 임시 파일을 삭제하지 않으면 65535에서이 함수를 호출하면 실패하게됩니다.
블라디미르 바라 노프

7
당신은 혼합이 GetTempFileName()GetRandomFileName(). GetTempFileName()내 방법과 같은 0 바이트 파일을 GetRandomFileName()만들지 만 파일을 만들지는 않습니다. 문서에서 :> GetTempFileName과 달리 GetRandomFileName은 파일을 만들지 않습니다. 링크가 잘못된 페이지를 가리 킵니다.
Maxence

19

또는 System.CodeDom.Compiler.TempFileCollection을 대신 사용할 수도 있습니다 .

string tempDirectory = @"c:\\temp";
TempFileCollection coll = new TempFileCollection(tempDirectory, true);
string filename = coll.AddExtension("txt", true);
File.WriteAllText(Path.Combine(tempDirectory,filename),"Hello World");

여기서는 txt 확장자를 사용했지만 원하는 것을 지정할 수 있습니다. 또한 사용 후 임시 파일이 유지되도록 keep 플래그를 true로 설정했습니다. 불행히도 TempFileCollection은 확장명마다 하나의 임의 파일을 만듭니다. 임시 파일이 더 필요한 경우 TempFileCollection의 여러 인스턴스를 만들 수 있습니다.


10

파일이 존재하지 않는 이유는 무엇입니까?

string fileName;
do
{
    fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".csv";
} while (System.IO.File.Exists(fileName));

9
File.Exists는 과거에 대한 정보를 알려주므로 신뢰할 수 없습니다. File.Exist의 반환과 코드 실행 사이에서 파일을 만들 수 있습니다.
JaredPar

4
... 그렇다면 당신은 아마도 당신 자신의 프로그램으로 안전 할 것입니다. 그러나 다른 프로세스가 정확히 같은 목적지에 파일을 쓰는 것은 아닙니다.
Koen

@JaredPar와이 일의 가능성은 무엇입니까?
Migol

2
@Migol 그것은 매우 낮으며, 정의상 예외적 인 조건입니다. 흠, 정확히 어떤 예외가 사용되도록 설계 되었습니까?
코디 그레이

3
guid 충돌의 @CodyGray 확률은 1 / 2 ^ 128입니다. 2 번 일어날 확률은 1 / 2 ^ 256입니다. 귀찮게하지 마십시오!
Migol

9

C ++의 GetTempFileName에 대한 MSDN 설명서 는 사용자의 우려 사항을 설명하고 이에 대한 답변을 제공합니다.

GetTempFileName은 파일 이름이 고유하다는 것을 보장 할 수 없습니다 .

uUnique 매개 변수의 하위 16 비트 만 사용됩니다. lpPathName 및 lpPrefixString 매개 변수가 동일하게 유지되면 GetTempFileName을 최대 65,535 개의 고유 파일 이름으로 제한합니다.

파일 이름을 생성하는 데 사용 된 알고리즘으로 인해 동일한 접두사로 많은 수의 파일을 만들 때 GetTempFileName의 성능이 저하 될 수 있습니다. 이러한 경우 GUID를 기반으로 고유 한 파일 이름을 구성하는 것이 좋습니다 .


2
GetTempFileName 메소드는 이전 임시 파일을 삭제하지 않고 65535 개 이상의 파일을 작성하는 데 사용되는 경우 IOException을 발생시킵니다. 사용 가능한 고유 임시 파일 이름이 없으면 GetTempFileName 메소드는 IOException을 발생시킵니다. 이 오류를 해결하려면 불필요한 모든 임시 파일을 삭제하십시오.
Max Hodges

불완전한 인용입니다. 관련 인용문 : " uUnique가 0이 아닌 경우 파일을 직접 작성해야합니다. GetTempFileName은 파일 이름이 고유함을 보장 할 수 없으므로 파일 이름 만 작성됩니다." 모든 사람들이 여기서 논의하는 방식으로 부르면 uUnique는 0이됩니다.
jnm2

6

어때요?

Path.Combine(Path.GetTempPath(), DateTime.Now.Ticks.ToString() + "_" + Guid.NewGuid().ToString() + ".csv")

컴퓨터가 동일한 순간에 동일한 Guid를 생성하는 것은 매우 불가능합니다. 내가 여기에 볼 수있는 유일한 약점은 DateTime.Now.Ticks가 성능에 미치는 영향입니다.


5

다음을 수행 할 수도 있습니다.

string filename = Path.ChangeExtension(Path.GetTempFileName(), ".csv");

그리고 이것은 또한 예상대로 작동합니다

string filename = Path.ChangeExtension(Path.GetTempPath() + Guid.NewGuid().ToString(), ".csv");

2
temp.csv 파일이 있고 temp.tmp를 만든 다음 확장자를 csv로 변경하면 실패합니다.
David

그렇지 않습니다 ... GetTempFileName ()은 고유 한 파일 이름을 만듭니다 ... 최대 32K의 한계까지 파일을 삭제해야하지만 솔루션이 정확하다고 생각합니다. 고유하지는 않지만 파일 경로를 ChangeExtension으로 전달하면 문제가 해결되지 않습니다.
Michael Prewecki

11
GetTempFileName은 반환되는 경로가 고유함을 보장합니다. 그것이 반환하는 경로 + ".csv"는 고유하지 않습니다. David가 말한 것처럼 이러한 방식으로 확장을 변경하면 실패 할 수 있습니다.
Marcus Griep

5
GetTempFileName은 파일을 생성하므로 첫 번째 예는 리소스 누출입니다.
Gary McGill

3

내 의견으로는, 대부분의 답변은 여기에 차선책으로 제안되었습니다. 가장 가까운 것은 Brann이 처음 제안한 것입니다.

임시 파일 이름은

  • 독특한
  • 충돌이 없음 (아직 존재하지 않음)
  • 원자 (같은 작업으로 이름과 파일 생성)
  • 추측하기 어렵다

이러한 요구 사항 때문에 그러한 짐승을 스스로 프로그래밍하는 것은 신의 생각이 아닙니다. IO 라이브러리를 작성하는 똑똑한 사람들은 (필요한 경우) 잠금과 같은 것에 대해 걱정합니다. 따라서 System.IO.Path.GetTempFileName ()을 다시 작성할 필요가 없습니다.

서투른 것처럼 보이더라도 작업을 수행해야합니다.

//Note that this already *creates* the file
string filename1 = System.IO.Path.GetTempFileName()
// Rename and move
filename = filename.Replace(".tmp", ".csv");
File.Move(filename1 , filename);

2
그러나 그것은 충돌이 없습니다. 'csv'는 이미 존재하고 덮어 쓸 수 있습니다.
xvan

3
File.MoveIOException대상 파일이 이미 존재 하면 발생합니다. msdn.microsoft.com/en-us/library/…
joshuanapoli

2

이것은 당신에게 도움이 될 수 있습니다 ... 그것은 임시 직원을 만드는 것입니다. 폴더에 넣고 VB.NET에서 문자열로 반환하십시오.

C #으로 쉽게 변환 가능 :

Public Function GetTempDirectory() As String
    Dim mpath As String
    Do
        mpath = System.IO.Path.Combine(System.IO.Path.GetTempPath, System.IO.Path.GetRandomFileName)
    Loop While System.IO.Directory.Exists(mpath) Or System.IO.File.Exists(mpath)
    System.IO.Directory.CreateDirectory(mpath)
    Return mpath
End Function

2

이것은 나에게 잘 작동하는 것 같습니다 : 파일 존재 여부를 확인하고 파일이 쓰기 가능한 위치인지 확인합니다. 제대로 작동하면 FileStream (일반적으로 임시 파일에 필요한 것)을 직접 반환하도록 변경할 수 있습니다.

private string GetTempFile(string fileExtension)
{
  string temp = System.IO.Path.GetTempPath();
  string res = string.Empty;
  while (true) {
    res = string.Format("{0}.{1}", Guid.NewGuid().ToString(), fileExtension);
    res = System.IO.Path.Combine(temp, res);
    if (!System.IO.File.Exists(res)) {
      try {
        System.IO.FileStream s = System.IO.File.Create(res);
        s.Close();
        break;
      }
      catch (Exception) {

      }
    }
  }
  return res;
} // GetTempFile

2

C #의 쉬운 기능 :

public static string GetTempFileName(string extension = "csv")
{
    return Path.ChangeExtension(Path.GetTempFileName(), extension);
}

GetTempFileName ()은 임시 폴더에 임시 파일을 만듭니다. 결과적으로 두 개의 임시 파일이 작성되며 그 중 하나는 누출됩니다.
evgenybf

1

인터넷에서 찾은 답변을 바탕으로 다음과 같이 코드를 작성합니다.

public static string GetTemporaryFileName()
{       
    string tempFilePath = Path.Combine(Path.GetTempPath(), "SnapshotTemp");
    Directory.Delete(tempFilePath, true);
    Directory.CreateDirectory(tempFilePath);
    return Path.Combine(tempFilePath, DateTime.Now.ToString("MMddHHmm") + "-" + Guid.NewGuid().ToString() + ".png");
}

Jay Hilyard의 C # Cookbook으로서 Stephen Teilhet은 애플리케이션에서 임시 파일 사용을 지적했습니다 .

  • 나중에 검색하기 위해 정보를 임시로 저장해야 할 때마다 임시 파일을 사용해야합니다.

  • 기억해야 할 것은 파일을 만든 응용 프로그램이 종료되기 전에이 임시 파일을 삭제하는 것입니다.

  • 삭제되지 않으면 사용자가 수동으로 삭제할 때까지 사용자의 임시 디렉토리에 남아 있습니다.


1

@Maxence@Mitch Wheat 답변을 혼합 하여 GetTempFileName 메서드의 의미 (fileName은 생성 된 새 파일의 이름)를 원합니다.

string GetNewTempFile(string extension)
{
    if (!extension.StartWith(".")) extension="." + extension;
    string fileName;
    bool bCollisions = false;
    do {
        fileName = Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString() + extension);
        try
        {
            using (new FileStream(fileName, FileMode.CreateNew)) { }
            bCollisions = false;
        }
        catch (IOException)
        {
            bCollisions = true;
        }
    }
    while (bCollisions);
    return fileName;
}

0

이것이 내가하고있는 일입니다.

문자열 tStamp = String.Format ( "{0 : yyyyMMdd.HHmmss}", DateTime.Now);
문자열 ProcID = Process.GetCurrentProcess (). Id.ToString ();
문자열 tmpFolder = System.IO.Path.GetTempPath ();
문자열 출력 파일 = tmpFolder + ProcID + "_"+ tStamp + ".txt";

양호 : 프로세스 식별자를 포함합니다. 불량 : 스레드 식별자를 포함하지 않습니다 (잠금 장치 내에서 실행할 수는 있지만) 나쁨 : 타임 스탬프의 해상도는 1 초입니다. 많은 응용 프로그램에서 초당 많은 파일을 생성하는 것이 일반적입니다.
andrewf

0

이는 증분 파일 이름을 생성하는 간단하지만 효과적인 방법입니다. 현재를 직접보고 (다른 곳을 쉽게 가리킬 수 있음) 기본 YourApplicationName * .txt를 사용하여 파일을 검색합니다 (다시 쉽게 변경할 수 있음). 첫 번째 파일 이름이 YourApplicationName0000.txt가되도록 0000에서 시작합니다. 어떤 이유로 든 왼쪽과 오른쪽 부분 사이에 정크가있는 파일 이름 (숫자가 아님)이있는 경우 tryparse 호출로 인해 해당 파일이 무시됩니다.

    public static string CreateNewOutPutFile()
    {
        const string RemoveLeft = "YourApplicationName";
        const string RemoveRight = ".txt";
        const string searchString = RemoveLeft + "*" + RemoveRight;
        const string numberSpecifier = "0000";

        int maxTempNdx = -1;

        string fileName;
        string [] Files = Directory.GetFiles(Directory.GetCurrentDirectory(), searchString);
        foreach( string file in Files)
        {
            fileName = Path.GetFileName(file);
            string stripped = fileName.Remove(fileName.Length - RemoveRight.Length, RemoveRight.Length).Remove(0, RemoveLeft.Length);
            if( int.TryParse(stripped,out int current) )
            {
                if (current > maxTempNdx)
                    maxTempNdx = current;
            }
        }
        maxTempNdx++;
        fileName = RemoveLeft + maxTempNdx.ToString(numberSpecifier) + RemoveRight;
        File.CreateText(fileName); // optional
        return fileName;
    }

-2

나는 당신이 이것을 시도해야한다고 생각합니다 :

string path = Path.GetRandomFileName();
path = Path.Combine(@"c:\temp", path);
path = Path.ChangeExtension(path, ".tmp");
File.Create(path);

고유 한 파일 이름을 생성하고 지정된 위치에 해당 파일 이름을 가진 파일을 작성합니다.


3
이 솔루션에는 많은 문제가 있습니다. C : \ temp를 절대 경로와 결합 할 수 없으며 c : \ temp를 쓸 수 없으며 파일의 .tmp 버전이 고유하다는 것을 보증하지 않습니다.
Mark Lakata
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.