I've got a array of class in which one member is the full path to a file. I need to delete all those files from the directory which is not included in the array. As Usual, I am using the convential compare and delete method. I need to know if there any fast way to accomplish this.
I heard it can be done using Linq, but i dont have knowledge on linq.
My class struct is like below.
Class ImageDetails
{
public string Title;
public Boolean CanShow;
public String PathToFile;
}
I have an array of ImageDetails. The PathToFile contains full path
}
You can use Except() to handle this:
var filesToDelete = Directory.GetFiles(Path.GetDirectoryName(yourClass.FilePath)).Except(yourClass.TheArray);
Why do you need to compare? If you have the full file name, then
File.Delete(fileName);
is all you need. The file IO is likely to be the slowest part of this, so I don't think Linq will make much difference to the performance.
If the file may not exist, then check for that first:
if (File.Exists(fileName))
{
File.Delete(fileName);
}
Edit: I see you mean that you want to delete the file if it is not in the array. I read your question to mean that the directory is not included in the array.
Still, the actual file deletion is likely to be the slowest part of this.
Related
I have a scenario in which I need much of the information from the FileInfo structure -- creation time, last write time, file size, etc. I need to be able to get this information cleanly, but also be able to truly unit test without hitting the file system.
I am using System.IO.Abstractions, so that gets me 99% of the way there for most of my class, except this one. I don't know how to use it to get the information I need from my MockFileSystem object.
public void Initialize(IFileSystem fs, string fullyQualifiedFileName)
{
string pathOnly = fs.Path.GetDirectoryName(fullyQualifiedFileName);
string fileName = fs.Path.GetFileName(fullyQualifiedFileName);
// Here's what I don't know how to separate out and mock
FileInfo fi = new FileInfo(fullyQualifiedFileName);
long size = fi.LongLength;
DateTime lastWrite = fi.LastWriteTime;
...
...
}
Any help on that line would be greatly appreciated.
UPDATE:
This is not an exact duplicate of existing questions because I'm asking how do I do it with System.IO.Abstractions, not how do I do it in general.
For those who are interested, I did find a way to accomplish it:
FileInfoBase fi = fs.FileInfo.FromFileName(fullFilePath);
If I use this line, I get the same information I need in both TEST and PROD environments.
https://github.com/TestableIO/System.IO.Abstractions/blob/5f7ae53a22dffcff2b5716052e15ff2f155000fc/src/System.IO.Abstractions/IFileInfo.cs
System.IO.Abstractions provides you with an IFileInfo interface to code against, which you could create your own implementation of to return the stats you're interested in testing against.
In this case you'd want another method to return an IFileInfo to your Initialize method, which could be virtual so that in your test it just returns your fake instead of really hitting the system.
I have another problem with my FileSystemWatcher ;)
Simply, what I want to do:
I want to watch specific folders, in order to add the paths of the files to a List(Of String) and set an integer-variable for each new file.
So:
I create the file "Test.png" and it does that:
(List) categoryFilesList.Add(e.FullPath)
(Integer-variable) counter += 1
Well, this is working well.
Now, if a file is deleted again, it should remove the path from the list and set the integer-variable down again. (-= 1).
This is working well, too, but now I have a problem, I am not able to find a solution for.
I have IncludeSubdirectories set to true to scan the subdirectories for files. On adding this works fine, but on removing it does not.
That is because I do NOT add folders to the list, only files. So, if I delete a folder, I am not able to know what content it was containing and how much files it were, because it is already gone.
But I would want to know, how many files there were in and what their paths were to remove them again from the list and set the integer-variable down again with the amount of deleted files.
I though about saving it anyway on changing, but I do not know how exactly and if this is a good idea.
Is there a better solution?
If something is unclear, then I am sorry, ask then.
I also accept C#-answers, VB.NET is just because my friend wants that.
Thanks!
My solution to a similar problem is as follows:
Ensure your FileSystemWatcher is configured to track subfolders. Once you do that, you should get a Delete event any time a folder or file is deleted. In the case where a folder is deleted, simply iterate through your collection and remove any items that contain the path of the folder.
For example:
int numRemoved = categoryFilesList.RemoveAll(
delegate(String s)
{
return s.Contains(<DeletedDirectoryPath>);
}
);
This would remove any items in your list which contain . You can then use numRemoved to maintain your file count. Alternatively, you could simply use the count of the list instead of maintaining your own copy of that data via the Count property on your list.
Additionally you should be sure that you handle the cases where items and directories are renamed so that your list of filenames is always up to date.
I am afraid that this isn't really possible to do, because of the way the deletion of a directory works in a system. The directory is deleted, but the files recursively are just part of the directory.
This was quite well described here on MSDN forums :
I you observe the behavior of the trash on your desktop, you will see
that each time you delete a folder, you can see that folder in the
trash but you cannot see the elements within that dropped folder. The
only way to see those elements is to recover the folder from the
trash.
I think it happens the same thing with the FSW class. When you delete
a folder inside a watched directory you only have the event of the
deleted folder because the folder and its contents is not really
deleted but only moved to the trash. This is why you never receive the
deleted events for the included files because they are still somewhere
on your system
According to this question here on SO, the same problem occurs when a folder is moved into the structure (and the question also shows the workaround to the moving issue).
Possible workaround for the deletion problem would be browsing the structure in advance and saving the amount of files in the directories into a tree-like structure, but it will definitely be much more complex than this. It would look like this:
public class DirectoryFiles
{
public int Count {get; set;}
public string FullPath {get; set;}
public List<DirectoryFiles> Subdirectories {get; set; }
}
private DirectoryFiles Initialize(string fullPath)
{
if (Directory.Exists(fullPath))
{
var toReturn = new DirectoryFiles { Subdirectories = new List<DirectoryFiles>() };
foreach (string directory in Directory.GetDirectories(fullPath))
{
toReturn.Subdirectories.Add(this.Initialize(directory));
}
toReturn.Count = toReturn.Subdirectories.Sum(x => x.Count) + Directory.GetFiles(fullPath).Count();
return toReturn;
}
else
{
throw new DirectoryNotFoundException(String.Format("Directory {0} does not exist", fullPath));
}
}
and in the class where you are counting:
private int GetCountOfFiles(DirectoryFiles files, string fullPath)
{
if (files.FullPath.Equals(fullPath, StringComparison.InvariantCultureIgnoreCase))
{
return files.Count;
}
foreach (var subdir in files.Subdirectories)
{
if (this.GetCountOfFiles(subdir, fullPath) != -1)
{
return subdir.Count;
}
}
return -1;
}
This may need improvements for:
Permissions - it will throw an exception if you don't have access to the files,
The performance is not perfect, on every subfile or subdirectory deletion you'll need to rebuild the whole structure. There can be some optimizations created for that as well, but should work quite well for smaller subdirectories. If you need performance improvements, I'll leave that to you. For that, consider adding DirectoryFiles Parent to DirectoryFiles and recount the directories on the way up.
I've got a 3 sets of 9 images in seperate .resx files, and I'm trying to figure out how to loop a single set into 9 static picture boxes.
Loop through all the resources in a .resx file
I've looked through some of the solutions in the above link, like using ResXResourceReader, but it comes up with a parsing error when I use the GetEnumerator method.
When I use the ResourceSet resourceSet = MyResourceClass.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true); line, there's no definition for the ResourceManager within the Form class, or a GetResourceSet method when I create my own ResourceManager.
There is actually a method called CreateFileBasedResourceManager which I've dabbled in, but truth be told I don't understand the parameters it needs too well aside from the directory.
I've also looked at some of the solutions involving assemblies and retrieving the executing image assembly at runtime, but I think that's a little out of my depth at the moment.
Can anyone tell me what I'm doing wrong with the first two methods or maybe something entirely different?
Looking at MSDN, you should be able to iterate the values from a RESX file like so:
string resxFile = #".\CarResources.resx";
// Get resources from .resx file.
using (ResXResourceSet resxSet = new ResXResourceSet(resxFile))
{
// Retrieve the image.
Object image = resxSet.GetObject("NAMEOFFILE", true);
}
If you wanted to iterate all objects in the RESX file, you could do something like this:
using (ResXResourceReader resxReader = new ResXResourceReader(resxFile))
{
foreach (DictionaryEntry entry in resxReader) {
// entry.Key is the name of the file
// entry.Value is the actual object...add it to the list of images you were looking to keep track of
}
}
More can be found here.
I known that this is a old question, but today I got the same problem, and solve setting the BasePath property, like this:
oResReader = new ResXResourceReader(strInputFile);
oResReader.BasePath = Path.GetDirectoryName(strInputFile);
I found this solution here
I'm using a document class. The first time, it was for the common files with methods like New(), Open(), Save().
New() and Open() returns a IDocument. Save doesn't return anything.
As you can see in the diagram above.
In my program, it must use xml or zip file extension. For the xml files there's any problem, all the methods are for it. But I've got problems with zip file. I was planning to do this, when the program executes Open(), extract all the xml files from the zip and returns all the files. But my Open() only returns a document.
I was planning of creating another property called CanExtract(), but maybe this is not a good idea. I just want to create a good design and understandable.
Change your Open() function to return an IEnumerable of IDocument:
public IEnumerable<IDocument> Open()
instead of
public IDocument Open()
Then when you open an xml file it returns an IEnumerable containing 1 IDocument and you can just use that one. When you open the zip file it returns all of the files in the zip as IDocuments inside the IEnumerable.
I would recommend changing your return property to be a List. Then you can process the list of documents with the same code whether there is 1 or 20 files returned.
You could also add overloads for creation and saving that accept multiple files and, if those overloads are used, you could perform automatic zipping.
I have a DB and a mapping framework which was written by the company Im working for. So I have a class for each table in the DB and those classes allow to call the DB and get various information in DataSets or DataTables for example. Now I am supposed to write that information to a TXT file in a certain format (I have the specs how it should look like). Its about estates, there will be many estates in a file and for each estates there are about 40 lines in the file. I know how to write to a file and stuff, what I am looking for is a good approach how to build this functionality in general.
This might be too general to give good advice, but is there a proven way to do such things?
Thanks :-)
Let's call the classes that give you table info TableInfo objects
I'd create an interface IDBInfoWriter, with a method WriteDBInfo(TableInfo ti)
Then an implementation of IDBInfoWriter, say DBInfoFileWriter, with a FileWriter as a private member. Each call to WriteDBInfo would dump whatever in the file writer
Finally a DBInfoWalker object, which would take a list of instantiated TableInfo and a IDbInfoWriter
class DBInfoWalker
function new(TableInfo[] tis, IDBInfoWriter idbiw)
{...}
function process()
{
for each TableInfo ti in tis
{
idbiw.WriteDBInfo(ti);
}
}
This way you can
Work on any subset of TableInfo you want (lets say you want just a list of TableInfo beginning with "S", pass only this list in the constructor of DBInfoWalker
Create as many output styles for your tableInfo, just create the correct implementation of IDBInfoWriter (network, unique file, multiple files, etc)
Of course, that's just one possibility :)
Good luck