I'm trying to compare two font collections in order to understand which fonts are already installed and which not.
Code is as follows:
var workingdir = new DirectoryInfo(Path.Combine(basepath, directory));
InstalledFontCollection col = new InstalledFontCollection();
PrivateFontCollection pcol = new PrivateFontCollection();
foreach (FileInfo fontname in workingdir.GetFiles("*.ttf"))
{
pcol.AddFontFile(fontname.FullName);
}
foreach (var item in pcol.Families)
{
if (col.Families.Contains(item))
{
Console.WriteLine(item.Name + " already installed");
}
else
{
Console.WriteLine(item.Name + " NOT INSTALLED");
}
}
Problem is that I know for sure that inside my workingdir there are some fonts already installed and some not, but the console output shows me that EVERY fontfile is not installed.
What am I missing? I guess there's something wrong in my logic but I don't understand where is the problem...
Contains checks if it is the same object with ==, but you have to check for the Names to be the same.
var workingdir = new DirectoryInfo(Path.Combine(basepath, directory));
var col = new InstalledFontCollection();
var pcol = new PrivateFontCollection();
foreach (var fontname in workingdir.GetFiles("*.ttf"))
{
pcol.AddFontFile(fontname.FullName);
}
foreach(var item in pcol.Families.Where(a => col.Families.Any(b => b.Name == a.Name)))
{
Console.WriteLine($"'{item.Name}' already installed");
}
Related
I can't remove the item using this type of loop (foreach), which loop should i use? (that will return my variables) if that makes any sense. Thank you all help is very much so appreciated! Be easy on me i'm not too experienced. If that doesn't make sense i'm really trying to find any way to basically make my program so that for each ip address, it will try my username and password combination (that are loaded into list like user:pass), i'm doing this because i have set up hundreds of proxies in the past with different user/pass & i'm checking to see if they work still. Thanks
var l = loadips();
var t = func();
Parallel.ForEach(l.ToArray(), (ip_item) =>
{
try
{
string ip = ip_item.IP;
try {
foreach (var blah2 in t)
{
String[] fc = blah2.test.Split(':');
var u = fc[0];
var p = fc[1];
using (var client = new ProxyClient(ip, u, p))
{
Console.WriteLine(u + p + ip_item.IP);
client.Connect();
ip_item.AcceptsConnection = client.IsConnected;
client.Disconnect();
}
}
}
catch
{
// t.Remove(blah2);
}
}
catch
{
Console.WriteLine(ip_item.IP + " - BAD!");
l.Remove(ip_item);
}
});
foreach (var item in l)
{
if (item.AcceptsConnection == true)
{
Console.WriteLine(ip + " Working proxy.");
}
}
}
Don't modify the collection through which you're iterating, whatever loop you use. To achieve your objective, simply add the working data to another list.
var working = new ConcurrentBag<IpItem>(); // not sure what your type is
[....]
using (var client = new ProxyClient(ip, u, p))
{
Console.WriteLine(u + p + ip_item.IP);
client.Connect();
ip_item.AcceptsConnection = client.IsConnected;
client.Disconnect();
working.Add(ip_item);
}
Then, at the end, get all working results from working, and output as needed
NO, you can't use foreach loop for removing an item from the collection; very basic reason because the loop iterator of foreach is ReadOnly. You should choose to use for loop for that purpose.
Check MSDN reference for foreach. As it clearly says
The foreach statement is used to iterate through the collection to get
the information that you want, but can not be used to add or remove
items from the source collection to avoid unpredictable side effects.
If you need to add or remove items from the source collection, use a
for loop.
Consider using another list to identify the failures.
var l = loadips();
var t = func();
var faileds = new ConcurrentQueue<YourClass>();
Parallel.ForEach(l.ToArray(), (ip_item) =>
{
try
{
...
}
catch
{
Console.WriteLine(ip_item.IP + " - BAD!");
faileds.Enqueue(ip_item);
}
});
foreach (var item in l.Except(faileds))
{
if (item.AcceptsConnection == true)
{
Console.WriteLine(ip + " Working proxy.");
}
}
And for "all combination", I suggest you list out all combinations first.
var combinations = l.SelectMany(ipItem =>
t.Select(blah2 => Tuple.Create(ipItem, blah2)).ToArray();
foreach (var combination in combinations)
{
var ip = combination.Item1.IP;
var fc = combination.Item2.Split(':');
var u = fc[0];
var p = fc[1];
...
}
I am trying to sort two folders in to a patched folder, finding which file is new in the new folder and marking it as new, so i can transfer that file only. i dont care about dates or hash changes. just what file is in the new folder that is not in the old folder.
somehow the line
pf.NFile = !( oldPatch.FindAll(s => s.Equals(f)).Count() == 0);
is always returning false. is there something wrong with my logic of cross checking?
List<string> newPatch = DirectorySearch(_newFolder);
List<string> oldPatch = DirectorySearch(_oldFolder);
foreach (string f in newPatch)
{
string filename = Path.GetFileName(f);
string Dir = (Path.GetDirectoryName(f).Replace(_newFolder, "") + #"\");
PatchFile pf = new PatchFile();
pf.Dir = Dir;
pf.FName = filename;
pf.NFile = !( oldPatch.FindAll(s => s.Equals(f)).Count() == 0);
nPatch.Files.Add(pf);
}
foreach (string f in oldPatch)
{
string filename = Path.GetFileName(f);
string Dir = (Path.GetDirectoryName(f).Replace(_oldFolder, "") + #"\");
PatchFile pf = new PatchFile();
pf.Dir = Dir;
pf.FName = filename;
if (!nPatch.Files.Exists(item => item.Dir == pf.Dir &&
item.FName == pf.FName))
{
nPatch.removeFiles.Add(pf);
}
}
I don't have the classes you are using (like DirectorySearch and PatchFile), so i can't compile your code, but IMO the line _oldPatch.FindAll(... doesn't return anything because you are comparing the full path (c:\oldpatch\filea.txt is not c:\newpatch\filea.txt) and not the file name only. IMO your algorithm could be simplified, something like this pseudocode (using List.Contains instead of List.FindAll):
var _newFolder = "d:\\temp\\xml\\b";
var _oldFolder = "d:\\temp\\xml\\a";
List<FileInfo> missing = new List<FileInfo>();
List<FileInfo> nPatch = new List<FileInfo>();
List<FileInfo> newPatch = new DirectoryInfo(_newFolder).GetFiles().ToList();
List<FileInfo> oldPatch = new DirectoryInfo(_oldFolder).GetFiles().ToList();
// take all files in new patch
foreach (var f in newPatch)
{
nPatch.Add(f);
}
// search for hits in old patch
foreach (var f in oldPatch)
{
if (!nPatch.Select (p => p.Name.ToLower()).Contains(f.Name.ToLower()))
{
missing.Add(f);
}
}
// new files are in missing
One possible solution with less code would be to select the file names, put them into a list an use the predefined List.Except or if needed List.Intersect methods. This way a solution to which file is in A but not in B could be solved fast like this:
var locationA = "d:\\temp\\xml\\a";
var locationB = "d:\\temp\\xml\\b";
// takes file names from A and B and put them into lists
var filesInA = new DirectoryInfo(locationA).GetFiles().Select (n => n.Name).ToList();
var filesInB = new DirectoryInfo(locationB).GetFiles().Select (n => n.Name).ToList();
// Except retrieves all files that are in A but not in B
foreach (var file in filesInA.Except(filesInB).ToList())
{
Console.WriteLine(file);
}
I have 1.xml, 2.xml, 3.xml in A and 1.xml, 3.xml in B. The output is 2.xml - missing in B.
I am trying to write to a ListView using the contents of 3 three already existing resx files. Using the following loop with only one of the files yields close to what I want but I need is to use the same loop with multiple DictionaryEntrys. What I am trying to do looks like this..
ResXResourceReader rdr0 = new ResXResourceReader(textPath1.Text + ".resx");
ResXResourceReader rdr1 = new ResXResourceReader(textPath1.Text + ".es.resx");
ResXResourceReader rdr2 = new ResXResourceReader(textPath1.Text + ".fr.resx");
foreach ((DictionaryEntry d in rdr0) && (DictionaryEntry e in rdr1))
{
string[] row = { d.Key.ToString(), d.Value.ToString(), e.Value.ToString() };
var listViewItem = new ListViewItem(row);
listResx.Items.Add(listViewItem);
}
The foreach keyword cannot do that.
Instead, you can use the LINQ .Zip() method:
foreach(var item in rdr0.Zip(rdr1, (d, e)
=> new [] { d.Key.ToString(), d.Value.ToString(), e.Value.ToString() }))
How can I check if a text file contains an item from a listbox. To stop saving duplicates. I'm not sure what I'd add to this. This is called on a button click event. For example, if a duplicate was found, I could show MessageBox.Show ("duplicate error");
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
foreach (object item in listBox2.Items)
{
writer.WriteLine(item.ToString());
}
}
Before writing to "test.txt", enumerate its contents:
var fileLines = File.ReadAllLines("test.txt");
List<string> fileItems = new List<string>(fileLines);
Then before you write each item, check to see if the list contains it:
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
foreach (object item in listBox2.Items)
{
if (fileItems.Contains(item))
// Do something, break, etc.
else
writer.WriteLine(item.ToString());
}
}
Edit:
Per suggestions, you can use a HashSet instead of a List for performance, as it can only contain unique values.
Another improvement may be to check if any duplicates exist before writing anything to the file. I've done that in the example below in a LINQ statement:
var fileLines = File.ReadAllLines("test.txt");
HashSet<string> fileItems = new HashSet<string>(fileLines);
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
bool duplicateFound = fileItems.Any(fi => listBox1.Items.Cast<string>().Any(i => i == fi));
if (duplicateFound)
MessageBox.Show("Duplicate items found.");
else
foreach (object item in listBox1.Items)
writer.WriteLine(item.ToString());
}
Edit 2:
As #Servy suggested, the listbox could contain duplicates, which should also be taken into consideration. Additionally, my HashSet implementation was sub-par. So in this third example, I am first checking if the listbox contains duplicates, then if any of the listbox items are already in the file. The usage of HashSet is more performant as well because I am not iterating it.
var fileLines = File.ReadAllLines("test.txt");
HashSet<string> fileItems = new HashSet<string>(fileLines);
List<string> duplicateListboxItems = listBox1.Items.Cast<string>().GroupBy(l => l).Where(g => g.Count() > 1).Select(g => g.Key).ToList();
if (duplicateListboxItems.Count > 0)
{
MessageBox.Show("The listbox contains duplicate entries.");
return;
}
bool duplicateFound = false;
List<string> outputItems = new List<string>();
foreach (string item in listBox1.Items)
{
if (fileItems.Contains(item))
{
MessageBox.Show(String.Format("The file has a duplicate: {0}", item));
duplicateFound = true;
break;
}
outputItems.Add(item);
}
if (duplicateFound)
return;
using (StreamWriter writer = new StreamWriter("test.txt", true))
{
foreach (string s in outputItems)
writer.WriteLine(s);
}
string filePath = "test.txt";
var existingLines = new HashSet<string>(File.ReadAllLines(filePath));
var linesToWrite = new List<string>();
foreach (string item in listBox2.Items)
{
if (existingLines.Add(item))
{
linesToWrite.Add(item);
}
else
{
//this is a duplicate!!!
}
}
File.AppendAllLines(filePath, linesToWrite);
I'm trying to read a file line by line, which works perfectly but I want to seperate the results I get into subitems in the listview.
I am also searching for all .jar files in the folder so I can use those as the name (first column). The second column needs to have the "version", the third column the "author" and the fourth column the "description".
Here's one of the text files I receive from within the jar files:
name: AFK
main: com.github.alesvojta.AFK.AFK
version: 2.0.5
author: Ales Vojta / schneckk
description: Provides AFK messages
website: http://dev.bukkit.org/server-mods/afk/
commands:
afk:
description: Provides AFK message when player types /afk.
usage: /<command>
this is the code I have right now:
private List<string> GetInstalledPlugins()
{
List<string> list = new List<string>();
lvInstalledPlugins.Items.Clear();
if (!Directory.Exists(Environment.CurrentDirectory + "\\plugins"))
{
Directory.CreateDirectory(Environment.CurrentDirectory + "\\plugins");
DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\plugins");
FileInfo[] fileInfo = di.GetFiles("*.jar");
foreach (var info in fileInfo)
{
//lvInstalledPlugins.Items.Add(info.Name);
list.Add(info.Name);
}
}
else
{
DirectoryInfo di = new DirectoryInfo(Environment.CurrentDirectory + "\\plugins");
FileInfo[] fileInfo = di.GetFiles("*.jar");
foreach (var info in fileInfo)
{
//lvInstalledPlugins.Items.Add(info.Name);
list.Add(info.Name);
}
}
return list;
}
private void test(IEnumerable<string> list)
{
List<ListViewItem> PluginList = new List<ListViewItem>();
var items = new string[4];
try
{
foreach (var ListItem in list)
{
Console.WriteLine(ListItem);
var name = Environment.CurrentDirectory + "\\plugins\\" + ListItem;
var zip = new ZipInputStream(File.OpenRead(name));
var filestream = new FileStream(name, FileMode.Open, FileAccess.Read);
var zipfile = new ZipFile(filestream);
ZipEntry item;
while ((item = zip.GetNextEntry()) != null)
{
if (item.Name == "plugin.yml")
{
using (var s = new StreamReader(zipfile.GetInputStream(item)))
{
string line;
while ((line = s.ReadLine()) != null)
{
if (line.Contains("name"))
{
items[0] = line;
}
if (line.Contains("version"))
{
items[1] = line;
}
if (line.Contains("author"))
{
items[2] = line;
}
if (line.Contains("description"))
{
items[3] = line;
}
try
{
var lvitem = new ListViewItem(items);
lvitem.Name = items[0];
lvitem.Text = items[0];
lvitem.SubItems.Add(items[1]);
lvitem.SubItems.Add(items[2]);
lvitem.SubItems.Add(items[3]);
PluginList.Add(lvitem);
}
catch (Exception)
{
}
}
lvInstalledPlugins.Items.AddRange(PluginList.ToArray());
}
}
}
}
This doesn't seem to work :/, any ideas? I've been working on this for the whole day and can't seem to get it to work :(.
Not exactly sure of your question, but going by the title, the answer to the question below may provide some assistance.
C# listView, how do I add items to columns 2, 3 and 4 etc?