回答:
読みやすさが重要でない場合は、GUIDを使用してください。
例えば:
var myUniqueFileName = string.Format(@"{0}.txt", Guid.NewGuid());
または短いです:
var myUniqueFileName = $@"{Guid.NewGuid()}.txt";
私のプログラムでは、読み取り可能な名前( "Image1.png"… "Image10.png")を生成するために、たとえば10回試行することがあり、失敗した場合(ファイルが既に存在するため)、GUIDにフォールバックします。
更新:
最近、DateTime.Now.TicksGUIDの代わりにも使用しています:
var myUniqueFileName = string.Format(@"{0}.txt", DateTime.Now.Ticks);
または
var myUniqueFileName = $@"{DateTime.Now.Ticks}.txt";
私にとっての利点は、GUIDと比較して、短くて「見栄えの良い」ファイル名が生成されることです。
場合によっては(たとえば、非常に短時間で多数のランダムな名前を生成する場合など)、これにより一意でない値が作成される可能性があることに注意してください。
他のコンピューターにファイルを転送する場合でも、ファイル名が一意であることを確認したい場合は、GUIDを使用してください。
DateTime.Now.Ticks.GetHashCode().ToString("x").ToUpper()
GetTempFileName()ようなファイルを削除せずに多数作成すると、例外がスローされる場合があります。
GetTempFileNameを作成します。これは、一時パスの場所を選択することも意味します。一方、別のパスで使用できるGetRandomFileName8.3 ファイル名を生成するのに適しています。(GetTempFileNameをFile.Deleteと共に使用して、他の場所でファイル名を使用するだけの恐ろしいコードを見たことがあります。)
System.IO.Path.GetRandomFileName()
ファイル名の読みやすさが重要でない場合は、多くの人が示唆しているように、GUIDで十分です。ただし、GUIDファイル名が1000のディレクトリを調べると、ソートが非常に困難であることがわかりました。したがって、私は通常、ファイル名にいくつかのコンテキスト情報を与える静的文字列、タイムスタンプ、およびGUIDの組み合わせを使用します。
例えば:
public string GenerateFileName(string context)
{
return context + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_" + Guid.NewGuid().ToString("N");
}
filename1 = GenerateFileName("MeasurementData");
filename2 = GenerateFileName("Image");
このように、ファイル名で並べ替えると、ファイルはコンテキスト文字列で自動的にグループ化され、タイムスタンプで並べ替えられます。
Windowsでのファイル名の制限は255文字であることに注意してください。
Right Click > Sort By > Dateます。ファイル名に日付と時刻を含めることは、できる限り冗長です。
Guid.NewGuid().ToString();。括弧がありません。それ以外の場合は+1
以下は、提供されたオリジナルに基づいて一意の読み取り可能なファイル名を返すアルゴリズムです。元のファイルが存在する場合、存在しないファイルが見つかるまで、ファイル名にインデックスを追加しようとします。既存のファイル名をHashSetに読み込んで衝突をチェックするため、かなり高速(私のマシンでは1秒あたり数百のファイル名)であり、スレッドセーフでもあり、競合状態の影響を受けません。
たとえば、それを渡すとtest.txt、次の順序でファイルを作成しようとします。
test.txt
test (2).txt
test (3).txt
など。最大試行回数を指定することも、デフォルトのままにすることもできます。
ここに完全な例があります:
class Program
{
static FileStream CreateFileWithUniqueName(string folder, string fileName,
int maxAttempts = 1024)
{
// get filename base and extension
var fileBase = Path.GetFileNameWithoutExtension(fileName);
var ext = Path.GetExtension(fileName);
// build hash set of filenames for performance
var files = new HashSet<string>(Directory.GetFiles(folder));
for (var index = 0; index < maxAttempts; index++)
{
// first try with the original filename, else try incrementally adding an index
var name = (index == 0)
? fileName
: String.Format("{0} ({1}){2}", fileBase, index, ext);
// check if exists
var fullPath = Path.Combine(folder, name);
if(files.Contains(fullPath))
continue;
// try to create the file
try
{
return new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write);
}
catch (DirectoryNotFoundException) { throw; }
catch (DriveNotFoundException) { throw; }
catch (IOException)
{
// Will occur if another thread created a file with this
// name since we created the HashSet. Ignore this and just
// try with the next filename.
}
}
throw new Exception("Could not create unique filename in " + maxAttempts + " attempts");
}
static void Main(string[] args)
{
for (var i = 0; i < 500; i++)
{
using (var stream = CreateFileWithUniqueName(@"c:\temp\", "test.txt"))
{
Console.WriteLine("Created \"" + stream.Name + "\"");
}
}
Console.ReadKey();
}
}
static readonly 変数でもなければlock?
私はGetRandomFileNameを使用します:
GetRandomFileNameメソッドは、フォルダー名またはファイル名のいずれかとして使用できる暗号的に強力なランダムな文字列を返します。GetTempFileNameとは異なり、GetRandomFileNameはファイルを作成しません。ファイルシステムのセキュリティが最も重要な場合は、GetTempFileNameの代わりにこのメソッドを使用する必要があります。
例:
public static string GenerateFileName(string extension="")
{
return string.Concat(Path.GetRandomFileName().Replace(".", ""),
(!string.IsNullOrEmpty(extension)) ? (extension.StartsWith(".") ? extension : string.Concat(".", extension)) : "");
}
カスタムメソッドを使用せずに、一意のファイル名を自動的に生成できます。ただで以下を使用しStorageFolderクラス またはStorageFileクラス。ここでの鍵は次のとおりです。CreationCollisionOption.GenerateUniqueNameとNameCollisionOption.GenerateUniqueName
一意のファイル名で新しいファイルを作成するには:
var myFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("myfile.txt", NameCollisionOption.GenerateUniqueName);
一意のファイル名を持つ場所にファイルをコピーするには:
var myFile2 = await myFile1.CopyAsync(ApplicationData.Current.LocalFolder, myFile1.Name, NameCollisionOption.GenerateUniqueName);
移動先の場所に一意のファイル名を持つファイルを移動するには:
await myFile.MoveAsync(ApplicationData.Current.LocalFolder, myFile.Name, NameCollisionOption.GenerateUniqueName);
宛先の場所で一意のファイル名を使用してファイルの名前を変更するには:
await myFile.RenameAsync(myFile.Name, NameCollisionOption.GenerateUniqueName);
私は次のコードとその正常な動作を使用しています。これがお役に立てば幸いです。
タイムスタンプを使用して一意のファイル名から始めます-
"context_" + DateTime.Now.ToString( "yyyyMMddHHmmssffff")
C#コード-
public static string CreateUniqueFile(string logFilePath, string logFileName, string fileExt)
{
try
{
int fileNumber = 1;
//prefix with . if not already provided
fileExt = (!fileExt.StartsWith(".")) ? "." + fileExt : fileExt;
//Generate new name
while (File.Exists(Path.Combine(logFilePath, logFileName + "-" + fileNumber.ToString() + fileExt)))
fileNumber++;
//Create empty file, retry until one is created
while (!CreateNewLogfile(logFilePath, logFileName + "-" + fileNumber.ToString() + fileExt))
fileNumber++;
return logFileName + "-" + fileNumber.ToString() + fileExt;
}
catch (Exception)
{
throw;
}
}
private static bool CreateNewLogfile(string logFilePath, string logFile)
{
try
{
FileStream fs = new FileStream(Path.Combine(logFilePath, logFile), FileMode.CreateNew);
fs.Close();
return true;
}
catch (IOException) //File exists, can not create new
{
return false;
}
catch (Exception) //Exception occured
{
throw;
}
}
ファイル名に日付のタイムスタンプが必要ですか?
ファイル名をGUIDにすることができます。
を使用Guid.NewGuid()してGUIDを作成し、それをファイル名(または、必要に応じてタイムスタンプと一緒にファイル名の一部)として使用するのはどうでしょう。
ファイル拡張子の前にシーケンス番号を追加することにより、Windowsのようにファイル名を生成する単純な再帰関数を作成しました。
の目的のファイルパスがC:\MyDir\MyFile.txtあり、ファイルがすでに存在する場合、最終的なファイルパスのを返しますC:\MyDir\MyFile_1.txt。
これは次のように呼ばれます:
var desiredPath = @"C:\MyDir\MyFile.txt";
var finalPath = UniqueFileName(desiredPath);
private static string UniqueFileName(string path, int count = 0)
{
if (count == 0)
{
if (!File.Exists(path))
{
return path;
}
}
else
{
var candidatePath = string.Format(
@"{0}\{1}_{2}{3}",
Path.GetDirectoryName(path),
Path.GetFileNameWithoutExtension(path),
count,
Path.GetExtension(path));
if (!File.Exists(candidatePath))
{
return candidatePath;
}
}
count++;
return UniqueFileName(path, count);
}
以下のように一意のIDを作成できないのはなぜですか。
DateTime.Now.TicksとGuid.NewGuid()。ToString()を使用して結合し、一意のIDを作成できます。
DateTime.Now.Ticksが追加されると、一意のIDが作成された日時を秒単位で確認できます。
コードをご覧ください。
var ticks = DateTime.Now.Ticks;
var guid = Guid.NewGuid().ToString();
var uniqueSessionId = ticks.ToString() +'-'+ guid; //guid created by combining ticks and guid
var datetime = new DateTime(ticks);//for checking purpose
var datetimenow = DateTime.Now; //both these date times are different.
一意のIDのティックの一部を取得し、後で参照できるように日付と時刻を確認することもできます。
作成した一意のIDをファイル名に添付するか、アプリケーションまたはWebサイトへのユーザーのログイン/ログアウト用の一意のセッションIDを作成するために使用できます。
Guid.NewGuid(その事実を無視して、「暗号的にランダム」ではない場合もあります)、そうでない場合は気にしないほど高い確率で、一意のIDが生成される-これは「ティック」よりはるかに高い保証です。したがって、「ティック」には値/値がありません。ここでは、「セカンダリ」データがファイル名に入力されていると想定しています。
私は通常これらの線に沿って何かをします:
work.dat1たとえば)work.2011-01-15T112357.dat例えば)work.2011-01-15T112357.0001.datたとえば、(GUIDは嫌いです。順序/予測可能性を好みます。)これがサンプルクラスです:
static class DirectoryInfoHelpers
{
public static FileStream CreateFileWithUniqueName( this DirectoryInfo dir , string rootName )
{
FileStream fs = dir.TryCreateFile( rootName ) ; // try the simple name first
// if that didn't work, try mixing in the date/time
if ( fs == null )
{
string date = DateTime.Now.ToString( "yyyy-MM-ddTHHmmss" ) ;
string stem = Path.GetFileNameWithoutExtension(rootName) ;
string ext = Path.GetExtension(rootName) ?? ".dat" ;
ext = ext.Substring(1);
string fn = string.Format( "{0}.{1}.{2}" , stem , date , ext ) ;
fs = dir.TryCreateFile( fn ) ;
// if mixing in the date/time didn't work, try a sequential search
if ( fs == null )
{
int seq = 0 ;
do
{
fn = string.Format( "{0}.{1}.{2:0000}.{3}" , stem , date , ++seq , ext ) ;
fs = dir.TryCreateFile( fn ) ;
} while ( fs == null ) ;
}
}
return fs ;
}
private static FileStream TryCreateFile(this DirectoryInfo dir , string fileName )
{
FileStream fs = null ;
try
{
string fqn = Path.Combine( dir.FullName , fileName ) ;
fs = new FileStream( fqn , FileMode.CreateNew , FileAccess.ReadWrite , FileShare.None ) ;
}
catch ( Exception )
{
fs = null ;
}
return fs ;
}
}
アルゴリズムを微調整したい場合があります(たとえば、常にファイル名に可能なすべてのコンポーネントを使用します)。コンテキストに依存する-たとえば、ログファイルを作成していて、存在しないようにローテーションしたい場合は、それらすべてに同じパターンの名前を共有する必要があります。
コードは完全ではありません(たとえば、渡されたデータのチェックはありません)。そして、アルゴリズムは完全ではありません(たとえば、ハードドライブをいっぱいにするか、アクセス許可、実際のI / Oエラー、またはその他のファイルシステムエラーが発生した場合、これは、現状では無限ループでハングします)。
Random.Next()を使用して乱数を生成することもできます。あなたはMSDNリンクを見ることができます:http: //msdn.microsoft.com/en-us/library/9b3ta19y.aspx
私はこれを行うために特別にクラスを書きました。「基本」部分(デフォルトは分単位の正確なタイムスタンプ)で初期化され、その後、一意の名前を付けるために文字を追加します。したがって、最初に生成されたスタンプが1907101215aの場合、2番目は1907101215b、次に1907101215cなどとなります。
25を超える一意のスタンプが必要な場合は、単項「z」を使用して25をカウントします。したがって、1907101215y、1907101215za、1907101215zb、... 1907101215zy、1907101215zza、1907101215zzbなどになります。これにより、スタンプは常に生成された順序で英数字順にソートされます(スタンプの後の次の文字が文字でない限り)。
それはスレッドセーフではなく、時間を自動的に更新せず、何百ものスタンプが必要な場合はすぐに膨張しますが、私のニーズには十分です。
/// <summary>
/// Class for generating unique stamps (for filenames, etc.)
/// </summary>
/// <remarks>
/// Each time ToString() is called, a unique stamp is generated.
/// Stamps are guaranteed to sort alphanumerically in order of generation.
/// </remarks>
public class StampGenerator
{
/// <summary>
/// All the characters which could be the last character in the stamp.
/// </summary>
private static readonly char[] _trailingChars =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y'
};
/// <summary>
/// How many valid trailing characters there are.
/// </summary>
/// <remarks>Should always equal _trailingChars.Length</remarks>
public const int TRAILING_RANGE = 25;
/// <summary>
/// Maximum length of the stamp. Hard-coded for laziness.
/// </summary>
public const int MAX_LENGTH_STAMP = 28;
/// <summary>
/// Base portion of the stamp. Will be constant between calls.
/// </summary>
/// <remarks>
/// This is intended to uniquely distinguish between instances.
/// Default behavior is to generate a minute-accurate timestamp.
/// </remarks>
public string StampBase { get; }
/// <summary>
/// Number of times this instance has been called.
/// </summary>
public int CalledTimes { get; private set; }
/// <summary>
/// Maximum number of stamps that can be generated with a given base.
/// </summary>
public int MaxCalls { get; }
/// <summary>
/// Number of stamps remaining for this instance.
/// </summary>
public int RemainingCalls { get { return MaxCalls - CalledTimes; } }
/// <summary>
/// Instantiate a StampGenerator with a specific base.
/// </summary>
/// <param name="stampBase">Base of stamp.</param>
/// <param name="calledTimes">
/// Number of times this base has already been used.
/// </param>
public StampGenerator(string stampBase, int calledTimes = 0)
{
if (stampBase == null)
{
throw new ArgumentNullException("stampBase");
}
else if (Regex.IsMatch(stampBase, "[^a-zA-Z_0-9 \\-]"))
{
throw new ArgumentException("Invalid characters in Stamp Base.",
"stampBase");
}
else if (stampBase.Length >= MAX_LENGTH_STAMP - 1)
{
throw new ArgumentException(
string.Format("Stamp Base too long. (Length {0} out of {1})",
stampBase.Length, MAX_LENGTH_STAMP - 1), "stampBase");
}
else if (calledTimes < 0)
{
throw new ArgumentOutOfRangeException(
"calledTimes", calledTimes, "calledTimes cannot be negative.");
}
else
{
int maxCalls = TRAILING_RANGE * (MAX_LENGTH_STAMP - stampBase.Length);
if (calledTimes >= maxCalls)
{
throw new ArgumentOutOfRangeException(
"calledTimes", calledTimes, string.Format(
"Called Times too large; max for stem of length {0} is {1}.",
stampBase.Length, maxCalls));
}
else
{
StampBase = stampBase;
CalledTimes = calledTimes;
MaxCalls = maxCalls;
}
}
}
/// <summary>
/// Instantiate a StampGenerator with default base string based on time.
/// </summary>
public StampGenerator() : this(DateTime.Now.ToString("yMMddHHmm")) { }
/// <summary>
/// Generate a unique stamp.
/// </summary>
/// <remarks>
/// Stamp values are orered like this:
/// a, b, ... x, y, za, zb, ... zx, zy, zza, zzb, ...
/// </remarks>
/// <returns>A unique stamp.</returns>
public override string ToString()
{
int zCount = CalledTimes / TRAILING_RANGE;
int trailing = CalledTimes % TRAILING_RANGE;
int length = StampBase.Length + zCount + 1;
if (length > MAX_LENGTH_STAMP)
{
throw new InvalidOperationException(
"Stamp length overflown! Cannot generate new stamps.");
}
else
{
CalledTimes = CalledTimes + 1;
var builder = new StringBuilder(StampBase, length);
builder.Append('z', zCount);
builder.Append(_trailingChars[trailing]);
return builder.ToString();
}
}
}
DateTime.Now.Ticks安全でGuid.NewGuid()はない、醜い、クリーンでほぼ安全なものが必要な場合(1ミリ秒で1,000,000回呼び出す場合など、100%安全ではありません)、次のことを試してください。
Math.Abs(Guid.NewGuid().GetHashCode())
安全とは、非常に短い期間に数ミリ秒の間に何度も呼び出す場合に一意であることを意味します。
GetHashCodeメソッドは、int32ビットの範囲を持つを返しますが、a GUIDは128ビットの範囲を持つため、一意である可能性が高くなります。GUID値の形式が気に入らない場合は、値を呼び出すだけでToString("N")ダッシュが削除されます。