I am working on localization and pulling all the available cultures based on the folders created in bin. the name of the folders are then converted into culturesInfo.
if (!bFoundInstalledCultures)
{
//determine which cultures are available to this application
Debug.WriteLine("Get Installed cultures:");
CultureInfo tCulture = new CultureInfo("");
foreach (string dir in Directory.GetDirectories(Application.StartupPath))
{
try
{
//see if this directory corresponds to a valid culture name
DirectoryInfo dirinfo = new DirectoryInfo(dir);
tCulture = CultureInfo.GetCultureInfo(dirinfo.Name);
//determine if a resources dll exists in this directory that matches the executable name
if (dirinfo.GetFiles(Path.GetFileNameWithoutExtension(Application.ExecutablePath) + ".resources.dll").Length > 0)
{
pSupportedCultures.Add(tCulture);
Debug.WriteLine(string.Format(" Found Culture: {0} [{1}]", tCulture.DisplayName, tCulture.Name));
}
}
catch(ArgumentException e) //ignore exceptions generated for any unrelated directories in the bin folder
{
}
}
bFoundInstalledCultures = true;
Above code is part of one Runtime localization example on Codeproject.com
are there are any methods thru which we can get this Info and can we use reflection.
Thanks in advance
You can use CultureInfo.GetCultures to get all installed cultures:
//create an array of CultureInfo to hold all the cultures found, these include the users local cluture, and all the
//cultures installed with the .Net Framework
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures & ~CultureTypes.NeutralCultures);
//loop through all the cultures found
foreach (CultureInfo culture in cultures)
{
// ...
}
Related
I wish to get list of all the folders/directories that has a particular file in it. How do I do this using C# code.
Eg: Consider I have 20 folders of which 7 of them have a file named "abc.txt". I wish to know all folders that has the file "abc.txt".
I know that we can do this by looking thru all the folders in the path and for each check if the File.Exists(filename); But I wish to know if there is any other way of doing the same rather than looping through all the folder (which may me little time consuming in the case when there are many folders).
Thanks
-Nayan
I would use the method EnumerateFiles of the Directory class with a search pattern and the SearchOption to include AllDirectories. This will return all files (full filename including directory) that match the pattern.
Using the Path class you get the directory of the file.
string rootDirectory = //your root directory;
var foundFiles = Directory.EnumerateFiles(rootDirectory , "abc.txt", SearchOption.AllDirectories);
foreach (var file in foundFiles){
Console.WriteLine(System.IO.Path.GetDirectoryName(file));
}
EnumerateFiles is only available since .NET Framework 4. If you are working with an older version of the .NET Framework then you could use GetFiles of the Directory class.
Update (see comment from PLB):
The code above will fail if the access to a directory in denied. In this case you will need to search each directory one after one to handle exceptions.
public static void SearchFilesRecursivAndPrintOut(string root, string pattern)
{
//Console.WriteLine(root);
try
{
var childDireactory = Directory.EnumerateDirectories(root);
var files = Directory.EnumerateFiles(root, pattern);
foreach (var file in files)
{
Console.WriteLine(System.IO.Path.GetDirectoryName(file));
}
foreach (var dir in childDireactory)
{
SearchRecursiv(dir, pattern);
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
The following shows how to narrow down your search by specific criteria (i.e. include only DLLs that contain "Microsoft", "IBM" or "nHibernate" in its name).
var filez = Directory.EnumerateFiles(#"c:\MLBWRT", "*.dll", SearchOption.AllDirectories)
.Where(
s => s.ToLower().Contains("microsoft")
&& s.ToLower().Contains("ibm")
&& s.ToLower().Contains("nhibernate"));
string[] allFiles = filez.ToArray<string>();
for (int i = 0; i < allFiles.Length; i++) {
FileInfo fInfo = new FileInfo(allFiles[i]);
Console.WriteLine(fInfo.Name);
}
I try to get the list of available Culture information, add them to a combobox and change the language on run time. My implementation acts different on different environments. There are some PCs where it works as expected, all the satellite assemblies are recognized, but on other PCs the same application does not recognize the available languages, only the default one (English).
This is my code where I try to find the available resource:
public static IEnumerable<CultureInfo> GetAvailableCultures()
{
List<CultureInfo> result = new List<CultureInfo>();
ResourceManager rm = new ResourceManager(typeof(PresentationResources));
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo culture in cultures)
{
try
{
if (culture.Equals(CultureInfo.InvariantCulture))
{
continue;
}
ResourceSet rs = rm.GetResourceSet(culture, true, false);
if (rs != null)
{
result.Add(culture);
}
}
catch (CultureNotFoundException)
{
//NOP
}
}
return result;
}
Also the code from the xaml from where I try to change the language:
<ComboBox Name="LanguageComboBox"
SelectedIndex="{Binding SelectedLanguageIndex}"
ItemsSource="{Binding AvailableLanguages}"
DisplayMemberPath="NativeName"
SelectedItem="{Binding Source={x:Static lex:LocalizeDictionary.Instance},
Path=Culture}"
SelectionChanged="LanguageComboBox_OnSelectionChanged">
</ComboBox>
I don't really understand why the exactly same application on some environments works as expected and on other ones not.
I want to parse a folder that the user can choose.
But if I understand, absolute paths are not allowed in UWP because the disks are not the same following the media (xbox, windows phone, windows desktop, ...) ?
So, I have a class called Parser that can parse the path that the user picks but now, only the current folder can be parsed.
This doesn't work :
Parser parser = new Parser(#"C:\a\b\c");
parser.createTreeView(tree);
Help me please. Thank you in advance.
EDIT : This is my Parser class =>
public TreeViewItem Parse(DirectoryInfo directoryInfo)
{
try
{
var directoryNode = new TreeViewItem { Header = directoryInfo.Name };
Convention convention = new Convention();
foreach (var directory in directoryInfo.GetDirectories())
{
directoryNode.Items.Add(Parse(directory));
System.Diagnostics.Debug.WriteLine("test : " + directory.Name);
}
foreach (var file in directoryInfo.GetFiles())
{
if (file.Name.Contains(EConvention.INSTALL))
{
listFiles.Add(file.FullName);
}
TreeViewItem item = new TreeViewItem
{
Header = Path.GetFileNameWithoutExtension(file.FullName),
Tag = file.FullName
};
directoryNode.Items.Add(item);
}
return directoryNode;
}
catch (System.UnauthorizedAccessException e)
{
//MessageDialog dialog = new MessageDialog(""+e.Message);
dialogAsync(e.Message);
return new TreeViewItem();
}
}
public void CreateTreeView(TreeView tree)
{
DirectoryInfo dir = new DirectoryInfo(pathToParse);
System.Diagnostics.Debug.WriteLine("dir exists ? "+dir.Exists);
if (dir.Exists)
{
System.Diagnostics.Debug.WriteLine("dir existe");
TreeViewItem root = new TreeViewItem() { Header = dir.Name };
root.Tag = dir;
tree.Items.Add(Parse(dir));
}
}
UWP apps do not have permission to access all files on the device. Apps can access certain file system locations by default. Apps can also access additional locations through the file picker, or by declaring capabilities. For more info, please see File access permissions
Although, we can use DirectoryInfo in UWP apps, but it can only work with the folders that UWP apps can access by default such as the install directory and local folder etc. Most types in the System.IO namespaces for UWP apps have the similar limitation. While dealing with files or folders in UWP, one important rule is Skip the path: stick to the StorageFile.
You can use a Folder​Picker to let the user choose a folder and then add it to your app's FutureAccessList or MostRecentlyUsedList to keep track of it. You can learn more about using these lists in How to track recently-used files and folders. After this, you will be able to retrieve the StorageFolder from FutureAccessList or MostRecentlyUsedList whenever you want to use it.
Once you have the StorageFolder, you can then use GetFilesAsync() or GetFoldersAsync() method in your Parse instead of DirectoryInfo.GetDirectories or DirectoryInfo.GetFiles method.
I have a simple method that counts the size of the directory and all files within it. Here is the code:
using System;
using System.IO;
namespace MyProject.Libs
{
public sealed class DirectorySize
{
public static long GetDirectorySize(DirectoryInfo dir)
{
long total = 0;
FileInfo[] fileInfos = dir.GetFiles();
foreach (FileInfo fileInfo in fileInfos)
{
total += fileInfo.Length;
}
DirectoryInfo[] dirInfos = dir.GetDirectories();
foreach (DirectoryInfo dirInfo in dirInfos)
{
total += DirectorySize.GetDirectorySize(dirInfo);
}
return total;
}
}
}
When I use it on drive c:\ I get "UnauthorizedAccessException" with a message "Access to the path 'C:\Documents and Settings' is denied." That is:
DirectoryInfo di = new DirectoryInfo(Path.GetPathRoot(Environment.SystemDirectory));
long ds = DirectorySize.GetDirectorySize(di);
Tried to run Visual Studio as Administrator. All the same. Why?
Your code fails on C:\Documents and Settings which is now a junction point that points to C:\Users. You could check that with the FileAttributes.ReparsePoint of the directory.
Here's the modified code with additional exception handling(for other dirs which you are not authorized):
public sealed class DirectorySize
{
public static long GetDirectorySize(DirectoryInfo dir)
{
long total = 0;
FileAttributes attributes = File.GetAttributes(dir.FullName);
if (!((attributes & FileAttributes.ReparsePoint) == FileAttributes.ReparsePoint))
{
try{
FileInfo[] fileInfos = dir.GetFiles();
foreach (FileInfo fileInfo in fileInfos)
{
total += fileInfo.Length;
}
DirectoryInfo[] dirInfos = dir.GetDirectories();
foreach (DirectoryInfo dirInfo in dirInfos)
{
total += DirectorySize.GetDirectorySize(dirInfo);
}
} catch (UnauthorizedAccessException)
{
// log this?
}
}
return total;
}
}
Junction Points (Windows)
In Windows Vista and Windows Server 2008, the default locations for
user data and system data have changed. For example, user data that
was previously stored in the %SystemDrive%\Documents and Settings
directory is now stored in the %SystemDrive%\Users directory. For
backward compatibility, the old locations have junction points that
point to the new locations. For example, C:\Documents and Settings is
now a junction point that points to C:\Users. Backup applications must
be capable of backing up and restoring junction points. These junction
points can be identified as follows: They have the
FILE_ATTRIBUTE_REPARSE_POINT, FILE_ATTRIBUTE_HIDDEN, and
FILE_ATTRIBUTE_SYSTEM file attributes set. They also have their access
control lists (ACLs) set to deny read access to everyone. Applications
that call out a specific path can traverse these junction points if
they have the required permissions. However, attempts to enumerate the
contents of the junction points will result in failures.
There are files and folders you don't have permissions to access, even as administrator. The best you can do is add some exception handling and hope the information you return is reasonably complete.
There are some folders where even the administrator has no permission to visit them. This most of the time happens with translated systems. For example the "program files" folder would be called "programme" in german. You have no access to "programme" within the code but to "program files"
I have a C# program that is using the standard ApplicationSettingsBase to save its user settings. This was working fine under .NET 3.5. And the provided Upgrade() method would properly "reload" those settings whenever a new version of my program was created.
Recently, I recompiled the program with .NET 4.0. My program's version number also increased. But, when I run this version, Upgrade() doesn't seem to to detect any previous version settings, and does not "reload" them. It starts blank.
As a test, I recompiled yet again, going back to .NET 3.5. And this time, the Upgrade() method started working again.
Is there a way to allow Upgrade() to work when switching frameworks? Is there something else I am missing?
I had exactly the same problem, and again I tested this several times from .NET 3.5 recomplied to .NET 4.0.
Unfortunately, my solution is in vb.net, but I'm sure you can use one of the many conversion programs to see this in c# such as http://www.developerfusion.com/tools/convert/vb-to-csharp/
It involves enumerating through all the folders in %AppData%\CompanyName to find the latest user.config file in a folder name of the version you wish to upgrade from.
I found that recompiling my app to .NET 4.0 under Visual Studio 2010 would create a new folder of name %AppData%\CompanyName\AppName.exe_Url_blahbahblah even though I had changed absolutely no other settings or code at all!
All my previous releases prior to .NET 4.0 retained the same folder name and upgraded successfully. Copying the old user.config file (and version folder name) from the old folder into the new folder structure created under .NET 4.0 (with the old version folder name) fixes the problem - it will now upgrade.
This example assumes you have a user setting named IUpgraded which is set to False by default (and later set to True) to check to see if the settings are initial defalt values or not - you may use any other variable you created instead. The example shows upgrading from version 1.2.0.0 to something later which you can change by changing the value of lastVersion.
The code is to be placed at the top of the form Load event of your latest (.NET 4.0) application version:
Imports System
Imports System.IO
If Not My.Settings.IUpgraded Then 'Upgrade application settings from previous version
My.Settings.Upgrade()
'The following routine is only relevant upgrading version 1.2.0.0
If Not My.Settings.IUpgraded Then 'enumerate AppData folder to find previous versions
Dim lastVersion As String = "1.2.0.0" 'version to upgrade settings from
Dim config_initial As System.Configuration.Configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.PerUserRoamingAndLocal)
Dim fpath As String = config_initial.FilePath
For x = 1 To 3 'recurse backwards to find root CompanyName folder
fpath = fpath.Substring(0, InStrRev(fpath, "\", Len(fpath) - 1))
Next
fpath = fpath.Substring(0, Len(fpath) - 1) 'remove trailing backslash
Dim latestConfig As FileInfo 'If not set then no previous info found
Dim di As DirectoryInfo = New DirectoryInfo(fpath)
If di.Exists Then
For Each diSubDir As DirectoryInfo In di.GetDirectories(lastVersion, SearchOption.AllDirectories)
If InStr(diSubDir.FullName, ".vshost") = 0 Then 'don't find VS runtime copies
Dim files() As FileInfo = diSubDir.GetFiles("user.config", SearchOption.TopDirectoryOnly)
For Each File As FileInfo In files
Try
If File.LastWriteTime > latestConfig.LastWriteTime Then
latestConfig = File
End If
Catch
latestConfig = File
End Try
Next
End If
Next
End If
Try
If latestConfig.Exists Then
Dim newPath As String = config_initial.FilePath
newPath = newPath.Substring(0, InStrRev(newPath, "\", Len(newPath) - 1))
newPath = newPath.Substring(0, InStrRev(newPath, "\", Len(newPath) - 1))
newPath &= lastVersion
If Directory.Exists(newPath) = False Then
Directory.CreateDirectory(newPath)
End If
latestConfig.CopyTo(newPath & "\user.config")
My.Settings.Upgrade() 'Try upgrading again now old user.config exists in correct place
End If
Catch : End Try
End If
My.Settings.IUpgraded = True 'Always set this to avoid potential upgrade loop
My.Settings.Save()
End If
Here is the code.
public static class SettingsUpdate
{
public static void Update()
{
try
{
var a = Assembly.GetExecutingAssembly();
string appVersionString = a.GetName().Version.ToString();
if( UserSettings.Default.internalApplicationVersion != appVersionString )
{
var currentConfig = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.PerUserRoamingAndLocal );
var exeName = "MyApplication.exe";
var companyFolder = new DirectoryInfo( currentConfig.FilePath ).Parent.Parent.Parent;
FileInfo latestConfig = null;
foreach( var diSubDir in companyFolder.GetDirectories( "*" + exeName + "*", SearchOption.AllDirectories ) )
{
foreach( var file in diSubDir.GetFiles( "user.config", SearchOption.AllDirectories ) )
{
if( latestConfig == null || file.LastWriteTime > latestConfig.LastWriteTime )
{
latestConfig = file;
}
}
}
if( latestConfig != null )
{
var lastestConfigDirectoryName = Path.GetFileName( Path.GetDirectoryName( latestConfig.FullName ) );
var latestVersion = new Version( lastestConfigDirectoryName );
var lastFramework35Version = new Version( "4.0.4605.25401" );
if( latestVersion <= lastFramework35Version )
{
var destinationFile = Path.GetDirectoryName( Path.GetDirectoryName( currentConfig.FilePath ) );
destinationFile = Path.Combine( destinationFile, lastestConfigDirectoryName );
if( !Directory.Exists( destinationFile ) )
{
Directory.CreateDirectory( destinationFile );
}
destinationFile = Path.Combine( destinationFile, latestConfig.Name );
File.Copy( latestConfig.FullName, destinationFile );
}
}
Properties.Settings.Default.Upgrade();
UserSettings.Default.Upgrade();
UserSettings.Default.internalApplicationVersion = appVersionString;
UserSettings.Default.Save();
}
}
catch( Exception ex )
{
LogManager.WriteExceptionReport( ex );
}
}
}
May this will help you :)
When Settings1.Upgrade() doesn't work as you espected, may try to delete previous user config files and try again.
In my case, Release and Debug versions are not correlative, then upgrade seems to fails because there is a conflict between versions in same directory related to debug/release outputs.
Clearing all previous user config files (appdata\local....) seems to solve the problem, calling Upgrade() works and the workaround proposed here works.
I hope it works for you.