.NET ile belirli bir uzantıya sahip geçici bir dosyayı nasıl oluşturabilirim?


277

.Csv uzantılı benzersiz bir geçici dosya oluşturmam gerekiyor.

Şu an yaptığım şey

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

Ancak, bu .csv dosyamın benzersiz olacağını garanti etmez.

Şimdiye kadar bir çarpışma var şansı biliyorum (özellikle .tmp dosyalarını silmiyorum düşünüyorsanız), ama bu kod bana iyi görünmüyor.

Tabii ki sonunda benzersiz bir tane bulana kadar rasgele dosya adları oluşturabilirim (ki bu bir sorun olmamalı), ancak başkalarının bu sorunla başa çıkmak için güzel bir yol bulup bulmadığını merak ediyorum.


4
GetTempFileName ile ilgili bazı uyarılar GetTempFileName yöntemi, önceki geçici dosyaları silmeden 65535'ten fazla dosya oluşturmak için kullanılıyorsa, bir IOException özel durumu oluşturur. Benzersiz bir geçici dosya adı yoksa, GetTempFileName yöntemi bir IOException özel durumu oluşturur. Bu hatayı gidermek için gereksiz tüm geçici dosyaları silin.
Max Hodges

2
Geçici dosyalar temel olarak belirli koşullar için kullanılır. Dosya uzantısı önemliyse, belki GetTempFileName kullanarak yazma çözümü olmadığını merak ediyorum. Uzun zaman geçtiğini biliyorum, ama bize bu dosyaların bağlamı ve ihtiyacı hakkında daha fazla bilgi verdiyseniz, daha iyi bir yaklaşım önerebiliriz. burada daha fazlasını bulabilirsiniz: support.microsoft.com/kb/92635?wa=wsignin1.0
Max Hodges

1
Unutmayın, her GetTempFileName() çağırışınızda yeni bir dosya oluşturur . - Dizeyi hemen başka bir şeye değiştirirseniz, geçici dizininizde yeni bir sıfır bayt dosyası oluşturdunuz (ve diğerlerinin belirttiği gibi, bu da 65535 dosyaya çarptığınızda başarısız olmasına neden olur ...) - - Bundan kaçınmak için, o klasörde oluşturduğunuz tüm dosyaları sildiğinizden emin olun GetTempFileName().
BrainSlugs83

Yanıtlar:


354

(İstatistiksel olarak) benzersiz olması garanti edilir:

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

(Çarpışma olasılığı hakkındaki wiki makalesinden alıntı yapmak için:

... kişinin bir göktaşı tarafından vurulma riskinin 17 milyarda bir şans olduğu tahmin edilmektedir [19], bu da olasılığın yaklaşık 0.00000000006 (6 × 10−11) olduğu ve birkaç on bir yıl içinde trilyonlarca UUID ve bir kopyası var. Başka bir deyişle, sadece önümüzdeki 100 yıl için her saniye 1 milyar UUID ürettikten sonra, sadece bir kopya oluşturma olasılığı yaklaşık% 50 olacaktır. Dünyadaki her insan 600 milyon UUID'ye sahipse, bir kopya olasılığı yaklaşık% 50 olacaktır.

EDIT: Lütfen ayrıca JaredPar'ın yorumlarına bakın.


29
Ancak yazılabilir bir yerde olması garanti edilmez
JaredPar

33
Ve bunların benzersiz olmaları garanti edilmez , sadece istatistiksel olarak olası değildir.
paxdiablo

30
@Pax: Piyangoyu arka arkaya 1000 kez kazanmak için iki idebtical kılavuz oluşturmaktan daha fazla şansınız var. Sanırım bu eşsiz ...
Mitch Wheat

11
@ Benzersiz olmamasının nedenini , aynı yolda aynı ada sahip bir dosya oluşturmamın mümkün olmasından kaynaklanıyor . Benzersiz olduğu garanti edilen GUID'ler de öngörülebilir, bu da yeterli bilgi verildiğinde, kutunuz tarafından oluşturulan bir sonraki kılavuz setini tahmin edebileceğim anlamına gelir
JaredPar

207
iyi efendiler, başınızı bulutlardan uzak tutmak için daha çok uğraşın. Yaklaşım şudur: rasgele bir dosya adı oluşturun, sonra yoksa oluşturun. Bu yüzden onu güzelce kodlamasına yardım edin. Sözde rastgele üreteçler ve evrensel olarak benzersiz sayılar hakkındaki tüm bu konuşma tamamen gereksizdir.
Max Hodges

58

Bu işlevi deneyin ...

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

Seçtiğiniz uzantı ile tam bir yol döndürür.

Unutmayın, başka biri teknik olarak zaten bu dosyayı yaratmış olabilir, çünkü benzersiz bir dosya adı üretmek garanti edilmez. Ancak birisinin uygulamanız tarafından üretilen bir sonraki rehberi tahmin etme ve oluşturma şansı çok düşüktür. Bunun benzersiz olacağını varsaymak oldukça güvenlidir.


4
Path.ChangeExtension (), Guid.NewGuid () 'den daha zarif olurdu. ToString () + uzantısı
Ohad Schneider

@ohadsc - gerçekten Guid.NewGuid().ToString() + extensiondoğru değil, olmalıGuid.NewGuid().ToString() + "." + extension
Stephen Swensen

4
Bu yöntemin sözleşmesine bağlı olduğunu varsayalım (ister beklensin .txtya da olsun txt) ama ChangeExtensionher iki durumu da ele
aldığından,

1
Uzatma yerine Suffix deyin ve herkes mutlu sanırım
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);
    }
  }
}

Not: Bu Path.GetTempFileName gibi çalışır. Dosya adını ayırmak için boş bir dosya oluşturulur. Path.GetRandomFileName () tarafından oluşturulan çakışmalar durumunda 10 deneme yapar;


Unutmayın Path.GetRandomFileName()aslında diskte sıfır bayt dosya oluşturur ve bu dosyanın tam yolunu döndürür. Bu dosyayı kullanmıyorsunuz, yalnızca uzantısını değiştirmek için adını kullanıyorsunuz. Bu nedenle, bu geçici dosyaları sildiğinizden emin değilseniz, 65535 bu işleve yapılan çağrılardan sonra başarısız olmaya başlayacaktır.
Vladimir Baranov

7
Karışık GetTempFileName()ve GetRandomFileName(). GetTempFileName()yöntemim gibi sıfır baytlık GetRandomFileName()bir dosya oluştur , ancak bir dosya oluşturmuyor. Dokümanlardan:> GetTempFileName öğesinin aksine, GetRandomFileName bir dosya oluşturmaz. Bağlantınız yanlış sayfayı gösteriyor.
Maxence

19

Alternatif olarak System.CodeDom.Compiler.TempFileCollection öğesini de kullanabilirsiniz .

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

Burada bir txt uzantısı kullandım ama ne istersen belirleyebilirsiniz. Ayrıca, kullanımdan sonra geçici dosyanın saklanabilmesi için keep flag'i true olarak ayarladım. Ne yazık ki, TempFileCollection her uzantı için bir rastgele dosya oluşturur. Daha fazla geçici dosyaya ihtiyacınız varsa, birden fazla TempFileCollection örneği oluşturabilirsiniz.


10

Dosyanın var olup olmadığını neden kontrol etmiyorsunuz?

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

9
File.Exists size geçmiş hakkında bilgi verir ve bu nedenle güvenilir değildir. File.Exist'in iadesi ve yürütme kodunuz arasında dosyanın oluşturulması mümkündür.
JaredPar

4
... o zaman belki kendi programınızla güvendesiniz ama aynı süreçte bir dosya yazan diğer süreçlerde değil ...
Koen

@JaredPar ve bunun gerçekleşme olasılığı nedir?
Migol

2
@Migol Çok düşük ve tanım gereği istisnai bir durum. Hmmm, tam olarak hangi istisnalar için kullanılmak üzere tasarlanmıştır.
Cody Gray

3
@CodyGray'in guid çakışması olasılığı 1/2 ^ 128'dir. 2 kez olma şansı 1/2 ^ 256 vb. Olduğunu. Rahatsız etmeyin!
Migol

9

C ++ 'ın GetTempFileName için MSDN belgeleri endişenizi tartışır ve yanıtlar:

GetTempFileName, dosya adının benzersiz olduğunu garanti edemez .

UUnique parametresinin yalnızca alt 16 biti kullanılır. Bu, lpPathName ve lpPrefixString parametreleri aynı kalırsa GetTempFileName öğesini en fazla 65.535 benzersiz dosya adıyla sınırlar.

Dosya adları oluşturmak için kullanılan algoritma nedeniyle, GetTempFileName aynı önekle çok sayıda dosya oluştururken düşük performans gösterebilir. Bu gibi durumlarda, GUID'lere dayalı benzersiz dosya adları oluşturmanız önerilir .


2
GetTempFileName yöntemi, önceki geçici dosyaları silmeden 65535'ten fazla dosya oluşturmak için kullanılırsa, bir IOException özel durumu oluşturur. Benzersiz bir geçici dosya adı yoksa, GetTempFileName yöntemi bir IOException özel durumu oluşturur. Bu hatayı gidermek için gereksiz tüm geçici dosyaları silin.
Max Hodges

Bu eksik bir teklif. İlgili alıntı: " uUnique sıfır değilse , dosyayı kendiniz oluşturmanız gerekir. GetTempFileName dosya adının benzersiz olduğunu garanti edemediğinden yalnızca bir dosya adı oluşturulur." Bunu herkesin burada tartıştığı şekilde adlandırırsanız, uUnique sıfır olacaktır.
jnm2

6

Nasıl olur:

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

Bilgisayarın aynı anda aynı Rehber'i üretmesi son derece olanaksızdır. Burada gördüğüm tek zayıflık DateTime.Now.Ticks ekleyecek performans etkisi.


5

Aşağıdakileri de yapabilirsiniz

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

ve bu da beklendiği gibi çalışıyor

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

2
temp.csv dosyası varsa ve temp.tmp dosyasını oluşturup uzantıyı csv olarak değiştirirseniz bu başarısız olur
David

Hayır olmaz ... GetTempFileName () benzersiz bir dosya adı oluşturur ... 32K sınırına kadar bazı dosyaları silmeniz gerekir ama benim çözümüm doğru olduğunu düşünüyorum. Benzersiz olduğu garanti edilmeyen bir dosya yolunu ChangeExtension'a geçirirsem yanlış olur, ancak benim çözümüm bu değildir.
Michael Prewecki

11
GetTempFileName döndürdüğü yolun benzersiz olacağını garanti eder. + ".Csv" döndürdüğü yol benzersiz olmayacak. David'in dediği gibi uzantıyı bu şekilde değiştirmek başarısız olabilir.
Marcus Griep

5
GetTempFileName bir dosya oluşturur, bu nedenle ilk örneğiniz bir kaynak sızıntısıdır.
Gary McGill

3

Benim düşünceme göre, çoğu cevap burada düşük optimal olarak önerildi. En yakın olan, başlangıçta Brann tarafından önerilen orijinal olan.

Geçici Dosya Adı olmalıdır

  • Benzersiz
  • Çatışma içermez (henüz mevcut değil)
  • Atomic (Aynı işlemde Ad ve Dosya Oluşturma)
  • Tahmin etmesi zor

Bu gereksinimler nedeniyle, böyle bir canavarı kendi başınıza programlamak tanrıça bir fikir değildir. IO Kütüphaneleri yazan Akıllı İnsanlar kilitleme (gerekirse) vb. Şeylerden endişe ediyor. Bu nedenle, System.IO.Path.GetTempFileName () 'i yeniden yazmaya gerek görmüyorum.

Bu, beceriksiz görünse bile, işi yapmalıdır:

//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
Ama bu çatışmadan bağımsız değil, 'csv' zaten var olabilir ve üzerine yazılabilirdi.
xvan

3
File.MoveIOExceptionhedef dosya zaten varsa yükseltir . msdn.microsoft.com/tr-tr/library/…
joshuanapoli

2

Bu sizin için kullanışlı olabilir ... Bir sıcaklık yaratmak. klasörüne gidin ve VB.NET'te dize olarak döndürün.

Kolayca C # dönüştürülebilir:

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

Bu benim için iyi çalışıyor gibi görünüyor: dosya varlığını kontrol eder ve yazılabilir bir konum olduğundan emin olmak için dosya oluşturur. İyi çalışıyorsa, doğrudan FileStream'e dönmek için değiştirebilirsiniz (normalde geçici bir dosya için ihtiyacınız olan şey budur):

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 # Kolay Fonksiyon:

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

GetTempFileName () geçici klasörde geçici bir dosya oluşturur. Sonuç olarak, biri sızacak olan iki geçici dosya oluşturulur.
evgenybf

1

İnternetten bulduğum cevaplara dayanarak koduma aşağıdaki gibi geliyorum:

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

Ve Jay Hilyard'ın C # Yemek Kitabı olarak Stephen Teilhet, Uygulamanızda Geçici Dosya Kullanmayı İşaret Etti :

  • bilgileri daha sonra almak için geçici olarak saklamanız gerektiğinde geçici bir dosya kullanmalısınız.

  • Hatırlamanız gereken tek şey, onu oluşturan uygulama sonlandırılmadan önce bu geçici dosyayı silmektir.

  • Silinmezse, kullanıcı el ile silene kadar kullanıcının geçici dizininde kalır.


1

Ben @Maxence ve @Mitch Wheat cevapları akılda tutarak karışık GetTempFileName yönteminin semantik istiyorum (fileName oluşturulan yeni bir dosya adıdır) tercih edilen uzantı ekleyerek.

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

Ben bunu yapıyorum:

string tStamp = String.Format ("{0: yyyyMMdd.HHmmss}", DateTime.Now);
string ProcID = Process.GetCurrentProcess (). Id.ToString ();
string tmpFolder = System.IO.Path.GetTempPath ();
string outFile = tmpFolder + ProcID + "_" + tStamp + ".txt";

İyi: işlem tanımlayıcısı içerir Kötü: iş parçacığı tanımlayıcısı içermez (bunu bir kilidin içinde çalıştırabilirsiniz) Kötü: zaman damgası yalnızca 1 saniyelik bir çözünürlüktür. Birçok uygulamada saniyede çok sayıda dosya üretmek yaygındır.
andrewf

0

Bu, artımlı dosya adları oluşturmanın basit ama etkili bir yoludur. Doğrudan doğruya bakacaktır (bunu başka bir yere kolayca işaret edebilirsiniz) ve YourApplicationName * .txt tabanına sahip dosyaları arayabilirsiniz (yine bunu kolayca değiştirebilirsiniz). İlk dosya adının UygulamanızAdı0000.txt olması için 0000'da başlayacaktır. herhangi bir nedenle sol ve sağ kısımlar arasında önemsiz (isim değil) olan dosya adları varsa, bu dosyalar tripparse çağrısı nedeniyle yok sayılır.

    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

Bence bunu denemelisin:

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

Benzersiz bir dosya adı oluşturur ve belirtilen bir konumda bu dosya adına sahip bir dosya oluşturur.


3
Bu çözümde çok fazla sorun var. C: \ temp ile mutlak bir yol birleştiremezsiniz, c: \ temp yazılabilir olmayabilir ve dosyanın .tmp sürümünün benzersiz olduğunu garanti etmez.
Mark Lakata
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.