Get file names from Resources sub folder - c#

In my Resources folder I have a subfolder for images, I would like to get all the file names of those images from within that folder.
tried several Resources.loadAll methods to afterwards get the .name but without success
was is the right practice to achieve what I'm trying to do here ?

There is no built-in API to do this because the information is not after you build. You cant' even do this with what's in the accepted answer. That would only work in the Editor. When you build the project, your code will fail.
Here's what to do:
1. Detect when the build button is clicked or when a build is about to happen in the OnPreprocessBuild function.
2. Get all the file names with Directory.GetFiles, serialize it to json and save it to the Resources folder. We use json to make it easier to read individual file name. You don't have to use json. You must exclude the ".meta" extension.
Step 1 and 2 are done in the Editor.
3. After a build or during run-time, you can access the saved file that contains the file names as a TextAsset with Resources.Load<TextAsset>("FileNames") then de-serialize the json from TextAsset.text.
Below is very simplified example. No error handling and that's up to you to implement. The Editor script below saves the file names when you click on the Build button:
[Serializable]
public class FileNameInfo
{
public string[] fileNames;
public FileNameInfo(string[] fileNames)
{
this.fileNames = fileNames;
}
}
class PreBuildFileNamesSaver : IPreprocessBuildWithReport
{
public int callbackOrder { get { return 0; } }
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
//The Resources folder path
string resourcsPath = Application.dataPath + "/Resources";
//Get file names except the ".meta" extension
string[] fileNames = Directory.GetFiles(resourcsPath)
.Where(x => Path.GetExtension(x) != ".meta").ToArray();
//Convert the Names to Json to make it easier to access when reading it
FileNameInfo fileInfo = new FileNameInfo(fileNames);
string fileInfoJson = JsonUtility.ToJson(fileInfo);
//Save the json to the Resources folder as "FileNames.txt"
File.WriteAllText(Application.dataPath + "/Resources/FileNames.txt", fileInfoJson);
AssetDatabase.Refresh();
}
}
During run-time, you can retrieve the saved file names with the example below:
//Load as TextAsset
TextAsset fileNamesAsset = Resources.Load<TextAsset>("FileNames");
//De-serialize it
FileNameInfo fileInfoLoaded = JsonUtility.FromJson<FileNameInfo>(fileNamesAsset.text);
//Use data?
foreach (string fName in fileInfoLoaded.fileNames)
{
Debug.Log(fName);
}

Hmm... why not try this.
using System.IO;
Const String path = ""; /file path
private void GetFiles()
{
string [] files = Directory.GetFiles (path, "*.*");
foreach (string sourceFile in files)
{
string fileName = Path.GetFileName (sourceFile);
Debug.Log("fileName");
}
}

Related

Searching through all subfolders when using Resources.Load in Unity

Is it possible to have Resources.Load(name, type) search for a fitting asset not just in the base Resources folder / a specified subfolder, but instead the full subfolder structure under Resources?
Example folder structure of
Resources
- Subfolder
- image.png
I would like something like Resources.Load("image", typeof(Texture2D)) to return the image without the user having to specify "Subfolder/image".
I know it's ugly, but it's supposed to be a "drop it in your bashed together project without worrying about your folder structure"-type utility script and I won't know the subfolder.
The accepted answer only works in the editor context, and doesn't work after building the game. The resources folder is packed when building your game, and will no longer be a file hierarchy you can loop through with Directory.GetDirectories. The only way to get this to work is to save all file paths while still in the editor context, and use this file hierarchy to load the assets at runtime. In my project I used the following code to add a button to the component that uses the assets in the resources folder, named CharacterGen. When this button is clicked, all png files in all subfolders in the Resources folder are saved to the public attribute named filePaths that CharacterGen has.
[CustomEditor(typeof(CharacterGen))]
public class RefreshCharacterList : Editor
{
CharacterGen charGen;
public void OnEnable()
{
charGen = (CharacterGen)target;
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
if (GUILayout.Button("Load resource paths"))
{
List<String> paths = new List<string>();
LoadPathsRecursive("", ref paths);
charGen.filePaths = paths;
EditorUtility.SetDirty(charGen); //original post didn't have this line, but this is needed to make sure your changes are saved.
}
}
void LoadPathsRecursive(string path, ref List<string> paths)
{
var fullPath = Application.dataPath + "/Resources/" + path;
Debug.Log("fullPath: " + fullPath);
DirectoryInfo dirInfo = new DirectoryInfo(fullPath);
foreach(var file in dirInfo.GetFiles())
{
if (file.Name.Contains(".PNG") && !file.Name.Contains(".meta"))
{
paths.Add(path + "/" + file.Name.Replace(".PNG", ""));
}
}
foreach (var dir in dirInfo.GetDirectories())
{
LoadPathsRecursive(path + "/" + dir.Name, ref paths);
}
}
}
In CharacterGen I later evoke Resources.Load, using the paths that were saved when clicking the button.
foreach (var filePath in filePaths)
{
var loadedSprite = Resources.Load<Sprite>(filePath);
//Do something with loadedSprite
}
Edit: I failed to mention an important detail in my original post. the filePaths is a Monobehaviour field, and I marked it with [SerializeField] (alternatively it could be marked as public) so that unity actually serializes the values of this field and includes it in the build.
There is no way to change the Resouces.Load() static method functionality, it's Unity Internal. However, you can write your own custom class that does your desired functionality. The code needs to find all the directories inside the Resources folder and search for the file. Let's call the class ResourcesExtension
public class ResourcesExtension
{
public static string ResourcesPath = Application.dataPath+"/Resources";
public static UnityEngine.Object Load(string resourceName, System.Type systemTypeInstance)
{
string[] directories = Directory.GetDirectories(ResourcesPath,"*",SearchOption.AllDirectories);
foreach (var item in directories)
{
string itemPath = item.Substring(ResourcesPath.Length+1);
UnityEngine.Object result = Resources.Load(itemPath+"\\"+resourceName,systemTypeInstance);
if(result!=null)
return result;
}
return null;
}
}
Then all you need to do is calling the static method.
ResourcesExtension.Load("image", typeof(Texture2D))
if you want to find all Object of a type and return as a List.
it Emad code Edited a bit.
private List<T> FindAllObject<T>()
{
List<T> tmp = new List<T>();
string ResourcesPath = Application.dataPath + "/Resources";
string[] directories = Directory.GetDirectories(ResourcesPath, "*", SearchOption.AllDirectories);
foreach (string item in directories)
{
string itemPath = item.Substring(ResourcesPath.Length + 1);
T[] reasult = Resources.LoadAll(itemPath, typeof(T)).Cast<T>().ToArray();
foreach (T x in reasult)
{
if (!tmp.Contains(x))
{
tmp.Add(x);
}
}
}
return tmp;
}
To use it.
List<MyClass> myClasses = FindAllObject<MyClass>();

Convert files following the order of a list C#

I need to convert images(like .jpg) to PDF files for an assignment for school. I have a ListBox where I put the pages of the PDF file, so the user can reorder the list and convert the files in that order.
I have the files in a temporary folder in order to get the files there to convert them to PDF.
My problem here is : how do I convert the files with the order that the user had chosen?
I already searched and I tried to do a Class with the strings ID and Name so i get the ID from the item in the ListBox and change it on a new list. And i think after, I do a foreach() loop where I get the files from the temporary folder and merge them in a new PDF file, but to do in the order I want, I think I have to compare the name of the file with the name in the list and, if it matches, convert and add it, if not, pass to the next file.
But I don't know how to do it.
Can please someone help me getting this right?
Thanks in advance!
I'm sending my code to:
//the open files button
private void proc2_Click(object sender, EventArgs e)
{
OpenFileDialog dialogo = new OpenFileDialog();
dialogo.Title = "Search files";
dialogo.InitialDirectory = #"E:\";
dialogo.Filter = "Images (.bmp,.jpg,.png,.tiff,.tif) |*.bmp;*.jpg;*.png;*tiff;*tif|All of the files (*.*)|*.*";
DialogResult resposta = dialogo.ShowDialog();
if (resposta == DialogResult.OK)
{
string caminhoCompleto = dialogo.FileName;
caminho2 = dialogo.SafeFileName;
caminhotb2.Text = caminhoCompleto;
string fish = "";
string path = #"C:\temporario";
if(Directory.Exists(path))
{
fish=Path.Combine(path, caminho2);
}
else
{
Directory.CreateDirectory(path);
fish = Path.Combine(path, caminho2);
}
File.Create(fish);
listaimg.Items.Add(caminho2);
}
}
public string[] GetFilesImg4() //jpg files
{
if (!Directory.Exists(#"C:\temporario"))
{
Directory.CreateDirectory(#"C:\temporario");
}
DirectoryInfo dirInfo = new DirectoryInfo(#"C:\temporario");
FileInfo[] fileInfos4 = dirInfo.GetFiles("*.jpg");
foreach (FileInfo info in fileInfos4)
{
if (info.Name.IndexOf("protected") == -1)
list4.Add(info.FullName);
}
return (string[])list4.ToArray(typeof(string));
}
If both actions happen in the same process, you can just store the list of file names in memory (and you already do add them to listaimg):
public string[] GetFilesImg4() //jpg files
{
string tempPath = #"C:\temporario";
if (!Directory.Exists(tempPath))
{
foreach (string filename in listimga.Items)
{
if (!filename.Contains("protected"))
list4.Add(Path.Combine(tempPath, filename);
}
}
return (string[])list4.ToArray(typeof(string));
}
if these are different processes then you can just dump content of your listimga at some point and then read it from the same file. In the example below I store it to file named "order.txt" in the same directory, but logic may be more complicated, such as merging several files with a timestamp and such.
// somewhere in after selecting all files
File.WriteAllLines(#"c:\temporario\order.txt", listimga.Items.Select(t=>t.ToString()));
public string[] GetFilesImg4() //jpg files
{
string tempPath = #"C:\temporario";
if (!Directory.Exists(tempPath))
{
var orderedFilenames = File.ReadAllLines(Path.Combine(tempPath, "order.txt")); // list of files loaded in order
foreach (string filename in orderedFilenames)
{
if (!filename.Contains("protected"))
list4.Add(Path.Combine(tempPath, filename);
}
}
return (string[])list4.ToArray(typeof(string));
}
it's also a good idea to examine available method on a class, such as in this case string.IndexOf(s) == -1 is equivalent to !string.Contains(s) and the latter is much more readable at least for an English speaking person.
I also noticed that your users have to select documents one by one, but FileOpen dialogs allow to select multiple files at a time, and I believe it preserves the order of selection as well.
If order of selection is important and file open dialogs don't preserve order or users find it hard to follow you can still use multiple file selection open dialog and then allow to reorder your listimga list box to get the order right.

Retrieve a list of files stored in a folder into my solution ASP.NET

I am not sure if I am in the right place to ask this, I am trying to create a table with all the PDF files that I have in a folder into my solution.
And I am trying to retrieve their names and put them in a table to access all of them throughout a link.
I got the following method, however, it not working.
protected void ListFiles()
{
const string MY_DIRECTORY = #"~/HistoricalFiles";
string strFile = null;
foreach (string s in Directory.GetFiles(Server.MapPath(MY_DIRECTORY), "*.*"))
{
strFile = s.Substring(s.LastIndexOf("\\") + 1);
//ListBox1.Items.Add(strFile);
}
}
Is there any way I can access all of them easily and display them in a good way?
By looking at your image, you should change the path of the folder. It is not in your root directory, it is inside Reports\API folder
const string MY_DIRECTORY = #"~/Reports/API/HistoricalFiles";

Programmatically extract the .dlls from clickonce application .deploy files

I have a click once application which is deployed on server (network share), is there a way programmatically that extract the .dlls from the .dll.deploy files. Once we launch the application, it converts into dlls and places in user/appdata/local/... folder, but I need a way to extract the dlls without launching the application.
Thanks for the help.
Simply rename the files by omitting the .deploy suffix and you're done.
Since this task could get a little tedious - depending on the number of files in your ClickOnce package - you might want to use a file renaming tool.
Update:
I just noticed that you were asking for a way to do this programmatically. That makes it even easier since you don't have to worry about finding a file renaming tool:
public class Program
{
private const string SourcePath = "\\\\ClickOnceDeployDir";
private const string TargetPath = "C:\\Users\\UserName\\Documents\\ClickOnceTargetDir";
public static void Main(string[] args)
{
var sourceDirectory = new DirectoryInfo(SourcePath);
var targetDirectory = new DirectoryInfo(TargetPath);
// you can omit this step if you would like to do the renaming in-place
Copy(sourceDirectory, targetDirectory);
foreach (var file in targetDirectory.GetFiles("*.deploy", SearchOption.AllDirectories))
{
var directoryName = file.DirectoryName;
if (directoryName != null)
{
// here it is: rename the file
file.MoveTo(Path.Combine(directoryName, Path.GetFileNameWithoutExtension(file.Name)));
}
}
}
private static void Copy(DirectoryInfo sourceDirectory, DirectoryInfo targetDirectory)
{
foreach (var file in sourceDirectory.GetFiles())
{
file.CopyTo(Path.Combine(targetDirectory.FullName, file.Name));
}
foreach (var directory in sourceDirectory.GetDirectories())
{
Copy(directory, targetDirectory.CreateSubdirectory(directory.Name));
}
}
}

read string from .resx file in C#

How to read the string from .resx file in c#? please send me guidelines . step by step
ResourceManager shouldn't be needed unless you're loading from an external resource.
For most things, say you've created a project (DLL, WinForms, whatever) you just use the project namespace, "Resources" and the resource identifier. eg:
Assuming a project namespace: UberSoft.WidgetPro
And your resx contains:
You can just use:
Ubersoft.WidgetPro.Properties.Resources.RESPONSE_SEARCH_WILFRED
This example is from the MSDN page on ResourceManager.GetString():
// Create a resource manager to retrieve resources.
ResourceManager rm = new ResourceManager("items", Assembly.GetExecutingAssembly());
// Retrieve the value of the string resource named "welcome".
// The resource manager will retrieve the value of the
// localized resource using the caller's current culture setting.
String str = rm.GetString("welcome");
Try this, works for me.. simple
Assume that your resource file name is "TestResource.resx", and you want to pass key dynamically then,
string resVal = TestResource.ResourceManager.GetString(dynamicKeyVal);
Add Namespace
using System.Resources;
Open .resx file and set "Access Modifier" to Public.
var <Variable Name> = Properties.Resources.<Resource Name>
Assuming the .resx file was added using Visual Studio under the project properties, there is an easier and less error prone way to access the string.
Expanding the .resx file in the Solution Explorer should show a .Designer.cs file.
When opened, the .Designer.cs file has a Properties namespace and an internal class. For this example assume the class is named Resources.
Accessing the string is then as easy as:
var resourceManager = JoshCodes.Core.Testing.Unit.Properties.Resources.ResourceManager;
var exampleXmlString = resourceManager.GetString("exampleXml");
Replace JoshCodes.Core.Testing.Unit with the project's default namespace.
Replace "exampleXml" with the name of your string resource.
Followed by #JeffH answer, I recommend to use typeof() than string assembly name.
var rm = new ResourceManager(typeof(YourAssembly.Properties.Resources));
string message = rm.GetString("NameOfKey", CultureInfo.CreateSpecificCulture("ja-JP"));
If for some reason you can't put your resources files in App_GlobalResources, then you can open resources files directly using ResXResourceReader or an XML Reader.
Here's sample code for using the ResXResourceReader:
public static string GetResourceString(string ResourceName, string strKey)
{
//Figure out the path to where your resource files are located.
//In this example, I'm figuring out the path to where a SharePoint feature directory is relative to a custom SharePoint layouts subdirectory.
string currentDirectory = Path.GetDirectoryName(HttpContext.Current.Server.MapPath(HttpContext.Current.Request.ServerVariables["SCRIPT_NAME"]));
string featureDirectory = Path.GetFullPath(currentDirectory + "\\..\\..\\..\\FEATURES\\FEATURENAME\\Resources");
//Look for files containing the name
List<string> resourceFileNameList = new List<string>();
DirectoryInfo resourceDir = new DirectoryInfo(featureDirectory);
var resourceFiles = resourceDir.GetFiles();
foreach (FileInfo fi in resourceFiles)
{
if (fi.Name.Length > ResourceName.Length+1 && fi.Name.ToLower().Substring(0,ResourceName.Length + 1) == ResourceName.ToLower()+".")
{
resourceFileNameList.Add(fi.Name);
}
}
if (resourceFileNameList.Count <= 0)
{ return ""; }
//Get the current culture
string strCulture = CultureInfo.CurrentCulture.Name;
string[] cultureStrings = strCulture.Split('-');
string strLanguageString = cultureStrings[0];
string strResourceFileName="";
string strDefaultFileName = resourceFileNameList[0];
foreach (string resFileName in resourceFileNameList)
{
if (resFileName.ToLower() == ResourceName.ToLower() + ".resx")
{
strDefaultFileName = resFileName;
}
if (resFileName.ToLower() == ResourceName.ToLower() + "."+strCulture.ToLower() + ".resx")
{
strResourceFileName = resFileName;
break;
}
else if (resFileName.ToLower() == ResourceName.ToLower() + "." + strLanguageString.ToLower() + ".resx")
{
strResourceFileName = resFileName;
break;
}
}
if (strResourceFileName == "")
{
strResourceFileName = strDefaultFileName;
}
//Use resx resource reader to read the file in.
//https://msdn.microsoft.com/en-us/library/system.resources.resxresourcereader.aspx
ResXResourceReader rsxr = new ResXResourceReader(featureDirectory + "\\"+ strResourceFileName);
//IDictionaryEnumerator idenumerator = rsxr.GetEnumerator();
foreach (DictionaryEntry d in rsxr)
{
if (d.Key.ToString().ToLower() == strKey.ToLower())
{
return d.Value.ToString();
}
}
return "";
}
I added the .resx file via Visual Studio. This created a designer.cs file with properties to immediately return the value of any key I wanted. For example, this is some auto-generated code from the designer file.
/// <summary>
/// Looks up a localized string similar to When creating a Commissioning change request, you must select valid Assignees, a Type, a Component, and at least one (1) affected unit..
/// </summary>
public static string MyErrorMessage {
get {
return ResourceManager.GetString("MyErrorMessage", resourceCulture);
}
}
That way, I was able to simply do:
string message = Errors.MyErrorMessage;
Where Errors is the Errors.resx file created through Visual Studio and MyErrorMessage is the key.
Once you add a resource (Name: ResourceName and Value: ResourceValue) to the solution/assembly, you could simply use "Properties.Resources.ResourceName" to get the required resource.
I added my resource file to my project directly, and so I was able to access the strings inside just fine with the resx file name.
Example: in Resource1.resx, key "resourceKey" -> string "dataString".
To get the string "dataString", I just put Resource1.resourceKey.
There may be reasons not to do this that I don't know about, but it worked for me.
The easiest way to do this is:
Create an App_GlobalResources system folder and add a resource file to it e.g. Messages.resx
Create your entries in the resource file e.g. ErrorMsg = This is an error.
Then to access that entry: string errormsg = Resources.Messages.ErrorMsg
The Simplest Way to get value from resource file.
Add Resource file in the project.
Now get the string where you want to add like in my case it was text block(SilverLight).
No need to add any namespace also.Its working fine in my case
txtStatus.Text = Constants.RefractionUpdateMessage;
Constants is my resource file name in the project.
Create a resource manager to retrieve resources.
ResourceManager rm = new ResourceManager("param1",Assembly.GetExecutingAssembly());
String str = rm.GetString("param2");
param1 = "AssemblyName.ResourceFolderName.ResourceFileName"
param2 = name of the string to be retrieved from the resource file
This works for me.
say you have a strings.resx file with string ok in it. to read it
String varOk = My.Resources.strings.ok
ResourceFileName.ResourceManager.GetString(ResourceFileName.Name)
2.return Resource.ResponseMsgSuccess;

Categories