[英]How to find the Filename with the latest version in C#
I have a folder that is filled with dwg files so I just need to find the latest version of a File or if a File has no versions then copy it to a directory. 我有一个充满dwg文件的文件夹,所以我只需要查找文件的最新版本,或者如果文件没有版本,则将其复制到目录中。 For example here are three files:
例如,这是三个文件:
ABBIE 08-10 #6-09H4 FINAL 06-12-2012.dwg
ABBIE 08-10#6-09H4决赛06-12-2012.dwg
ABBIE 08-10 #6-09H4 FINAL 06-12-2012_1.dwgABBIE 08-10#6-09H4决赛06-12-2012_1.dwg
ABBIE 08-10 #6-09H4 FINAL 06-12-2012_2.dwgABBIE 08-10#6-09H4决赛06-12-2012_2.dwg
Notice the difference is one file has a _1
and another has a _2
so the latest file here is the _2
. 请注意,区别在于一个文件具有
_1
,另一个文件具有_2
因此此处的最新文件是_2
。 I need to keep the latest file and copy it to a directory. 我需要保留最新文件并将其复制到目录中。 Some files will not have different versions so those can be copied.
某些文件不会具有不同的版本,因此可以将其复制。 I cannot focus on the creation date of the file or the modified date because in many instances they are the same so all I have to go on is the file name itself.
我不能专注于文件的创建日期或修改日期,因为在许多情况下它们是相同的,所以我要做的就是文件名本身。 I'm sure there is a more efficient way to do this than what I will post below.
我敢肯定有比我在下面发布的方法更有效的方法。
DirectoryInfo myDir = new DirectoryInfo(@"H:\Temp\Test");
var Files = myDir.GetFiles("*.dwg");
string[] fileList = Directory.GetFiles(@"H:\Temp\Test", "*FINAL*", SearchOption.AllDirectories);
ArrayList list = new ArrayList();
ArrayList WithUnderscores = new ArrayList();
string nameNOunderscores = "";
for (int i = 0; i < fileList.Length; i++)
{
//Try to get just the filename..
string filename = fileList[i].Split('.')[0];
int position = filename.LastIndexOf('\\');
filename = filename.Substring(position + 1);
filename = filename.Split('_')[0];
foreach (FileInfo allfiles in Files)
{
var withoutunderscore = allfiles.Name.Split('_')[0];
withoutunderscore = withoutunderscore.Split('.')[0];
if (withoutunderscore.Equals(filename))
{
nameNOunderscores = filename;
list.Add(allfiles.Name);
}
}
//If there is a number after the _ then capture it in an ArrayList
if (list.Count > 0)
{
foreach (string nam in list)
{
if (nam.Contains("_"))
{
//need regex to grab numeric value after _
var match = new Regex("_(?<number>[0-9]+)").Match(nam);
if (match.Success)
{
var value = match.Groups["number"].Value;
var number = Int32.Parse(value);
WithUnderscores.Add(number);
}
}
}
int removedcount = 0;
//Whats the max value?
if (WithUnderscores.Count > 0)
{
var maxval = GetMaxValue(WithUnderscores);
Int32 intmax = Convert.ToInt32(maxval);
foreach (FileInfo deletefile in Files)
{
string shorten = deletefile.Name.Split('.')[0];
shorten = shorten.Split('_')[0];
if (shorten == nameNOunderscores && deletefile.Name != nameNOunderscores + "_" + intmax + ".dwg")
{
//Keep track of count of Files that are no good to us so we can iterate to next set of files
removedcount = removedcount + 1;
}
else
{
//Copy the "Good" file to a seperate directory
File.Copy(@"H:\Temp\Test\" + deletefile.Name, @"H:\Temp\AllFinals\" + deletefile.Name, true);
}
}
WithUnderscores.Clear();
list.Clear();
}
i = i + removedcount;
}
else
{
//This File had no versions so it is good to be copied to the "Good" directory
File.Copy(@"H:\Temp\SH_Plats\" + filename, @"H:\Temp\AllFinals" + filename, true);
i = i + 1;
}
}
You can use this Linq query with Enumerable.GroupBy
which should work
(now tested): 您可以将此Linq查询与
Enumerable.GroupBy
一起使用,该查询
应该可以正常工作
(现已测试):
var allFiles = Directory.EnumerateFiles(sourceDir, "*.dwg")
.Select(path => new
{
Path = path,
FileName = Path.GetFileName(path),
FileNameWithoutExtension = Path.GetFileNameWithoutExtension(path),
VersionStartIndex = Path.GetFileNameWithoutExtension(path).LastIndexOf('_')
})
.Select(x => new
{
x.Path,
x.FileName,
IsVersionFile = x.VersionStartIndex != -1,
Version = x.VersionStartIndex == -1 ? new Nullable<int>()
: x.FileNameWithoutExtension.Substring(x.VersionStartIndex + 1).TryGetInt(),
NameWithoutVersion = x.VersionStartIndex == -1 ? x.FileName
: x.FileName.Substring(0, x.VersionStartIndex)
})
.OrderByDescending(x => x.Version)
.GroupBy(x => x.NameWithoutVersion)
.Select(g => g.First());
foreach (var file in allFiles)
{
string oldPath = Path.Combine(sourceDir, file.FileName);
string newPath;
if (file.IsVersionFile && file.Version.HasValue)
newPath = Path.Combine(versionPath, file.FileName);
else
newPath = Path.Combine(noVersionPath, file.FileName);
File.Copy(oldPath, newPath, true);
}
Here's the extension method which i'm using to determine if a string
is parsable to int
: 这是我用来确定
string
是否可解析为int
的扩展方法:
public static int? TryGetInt(this string item)
{
int i;
bool success = int.TryParse(item, out i);
return success ? (int?)i : (int?)null;
}
Note that i'm not using regex but string methods only. 请注意,我不使用正则表达式,而仅使用字符串方法。
I've made a Regex based solution, and apparently come late to the party in the meantime. 我提出了一个基于Regex的解决方案,显然在此期间晚了。
(?<fileName>[A-Za-z0-9-# ]*)_?(?<version>[0-9]+)?\\.dwg
this regex will recognise the fileName and version and split them into groups, a pretty simple foreach loop to get the most recent files in a dictionary (cos I'm lazy) and then you just need to put the fileNames back together again before you access them. 这个正则表达式将识别文件名和版本并将它们分成组,这是一个非常简单的foreach循环,以获取字典中的最新文件(因为我很懒),然后您只需要再次将文件名放回一起即可访问他们。
var fileName = file.Key + "_" + file.Value + ".dwg"
full code 完整的代码
var files = new[] {
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012.dwg",
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012_1.dwg",
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012_2.dwg",
"Second File.dwg",
"Second File_1.dwg",
"Third File.dwg"
};
// regex to split fileName from version
var r = new Regex( @"(?<fileName>[A-Za-z0-9-# ]*)_?(?<version>[0-9]+)?\.dwg" );
var latestFiles = new Dictionary<string, int>();
foreach (var f in files)
{
var parsedFileName = r.Match( f );
var fileName = parsedFileName.Groups["fileName"].Value;
var version = parsedFileName.Groups["version"].Success ? int.Parse( parsedFileName.Groups["version"].Value ) : 0;
if( latestFiles.ContainsKey( fileName ) && version > latestFiles[fileName] )
{
// replace if this file has a newer version
latestFiles[fileName] = version;
}
else
{
// add all newly found filenames
latestFiles.Add( fileName, version );
}
}
// open all most recent files
foreach (var file in latestFiles)
{
var fileToCopy = File.Open( file.Key + "_" + file.Value + ".dwg" );
// ...
}
Try this 尝试这个
var files = new My.Computer().FileSystem.GetFiles(@"c:\to\the\sample\directory", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dwg");
foreach (String f in files) {
Console.WriteLine(f);
};
NB: Add a reference to Microsoft.VisualBasic
and use the following line at the beginning of the class: 注意:添加对
Microsoft.VisualBasic
的引用,并在类的开头使用以下行:
using My = Microsoft.VisualBasic.Devices;
UPDATE 更新
The working sample[tested]: 工作样本[经测试]:
String dPath=@"C:\to\the\sample\directory";
var xfiles = new My.Computer().FileSystem.GetFiles(dPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dwg").Where(c => Regex.IsMatch(c,@"\d{3,}\.dwg$"));
XElement filez = new XElement("filez");
foreach (String f in xfiles)
{
var yfiles = new My.Computer().FileSystem.GetFiles(dPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, string.Format("{0}*.dwg",System.IO.Path.GetFileNameWithoutExtension(f))).Where(c => Regex.IsMatch(c, @"_\d+\.dwg$"));
if (yfiles.Count() > 0)
{
filez.Add(new XElement("file", yfiles.Last()));
}
else {
filez.Add(new XElement("file", f));
};
};
Console.Write(filez);
Can you do this by string sort? 可以按字符串排序吗? The only tricky part I see here is to convert the file name to a sortable format.
我在这里看到的唯一棘手的部分是将文件名转换为可排序的格式。 Just do a string replace from dd-mm-yyyy to yyyymmdd.
只需将字符串从dd-mm-yyyy替换为yyyymmdd。 Then, sort the the list and get the last record out.
然后,对列表进行排序并获取最后一条记录。
This is what you want considering fileList contain all file names 这就是您要考虑的文件列表包含所有文件名的原因
List<string> latestFiles=new List<string>();
foreach(var groups in fileList.GroupBy(x=>Regex.Replace(x,@"(_\d+\.dwg$|\.dwg$)","")))
{
latestFiles.Add(groups.OrderBy(s=>Regex.Match(s,@"\d+(?=\.dwg$)").Value==""?0:int.Parse(Regex.Match(s,@"\d+(?=\.dwg$)").Value)).Last());
}
latestFiles has the list of all new files.. LatestFiles包含所有新文件的列表。
If fileList is bigger,use Threading
or PLinq
如果fileList较大,请使用
Threading
或PLinq
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.