How to access batch file that I saved as a resource? - c#

I saved some batch file as a resource on my application.
I want to access this file on run time - so I trying to file this file on the Resource folder but I get an exception that the
"resource folder is not there"
I trying to find the resource file by this code
var allBatchFiles = Directory.GetFiles( string.Format( #"..\..\Resources\" ) );
So how to make this work ?

Note that, when you run your application in Visual Studio, it is executed from the bin subfolder, which changes relative paths.
However, if you want to embed the batch file into your application, you are entirely on the wrong track. The resource is compiled into your EXE, and you need to use a different method to retrieve it. The following MSDN article gives an example on how this can be done:
How to embed and access resources by using Visual C#

There are at least two types of resources you might be referring to.
First, if you are referring to a RESX file, then usually you can access resources directly. So if you have a RESX file called "MyRes.resx" with a resource in it called "MyString" then you can use:
string contents = Resources.MyRes.MyString;
If you are adding files to the solution and marking them as Embedded Resources, then you can use Assembly.GetManifestResourceStream to access the data. Here's the utility functions I use:
public static Stream GetResourceStream(string pathName, string resName, Assembly srcAssembly = null)
{
if (srcAssembly == null) srcAssembly = Assembly.GetCallingAssembly();
var allNames = srcAssembly.GetManifestResourceNames();
return srcAssembly.GetManifestResourceStream(pathName + "." + resName);
}
public static string GetResourceString(string pathName, string resName, Assembly srcAssembly = null)
{
if (srcAssembly == null) srcAssembly = Assembly.GetCallingAssembly();
StreamReader sr = new StreamReader(GetResourceStream(pathName, resName, srcAssembly));
string s = sr.ReadToEnd();
sr.Close();
return s;
}
The pathName is a bit tricky - it's the name of the project plus any folder names in your project. So if you have a project "MyApp" with a folder called "MyResources" with a file called "Batch.txt" marked as a resource, then you would access the contents with:
string contents = GetResourceString("MyApp.MyResources", "Batch.txt");

Related

cannot find the path to the resource file c#

firstly apology if this has already been answered and I am duplicating the question. I have tried to find the answer to my issue but have failed and none of the auto-suggestions answers my problem.
I have my main project (XAML) and also a class library project called FileStore for files. The class library project is referenced into the main project and I have images and icon file in the class library project that I can access with no issues in my main project, however, I struggle to get the content of a txt file from the CL project to display in a label on the main project. I get the error: the system could not find the file and from the error, I can see that it is trying to look for a file in the main project bin\debug folder
I tried to follow this previous post which seemed to partly answer my issue but to no avail sadly.
Get relative file path in a class library project that is being referenced by a web project
The txt file Build action is set to: Resource and Copy to Output Directory set to: Copy Always.
As I mentioned I have the FileStore project referenced in my main project and the images work fine.
Below is the code I am using, I have tried different variations such as:
\Resources\textFile.txt and \textFile.txt, still no luck.
'''
public static string ReadFileinClLibr()
{
var buildDir =
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var filePath = buildDir + #"\textFile.txt";
return File.ReadAllText(filePath);
}
'''
For comparition here is the path for the image files that works, but I cannot get it to work with the txt file, as the error reads: the given paths format is not supported..
'''
#"pack://application:,,,/FileStore;component/Resources\textFile.txt"
'''
I want to be able to input the content of the text file from the class library project to the label in the main xaml project.
At the moment compiler keeps looking for this file in a debug folder of the main project, what I want is, for the compiler to look for the txt file in a CL FileStore project
In order to access the file all the time, we have to have the file copied to the debug folder. Right click the file from solution explorer change the properties then try to access the file from the executing assembly location.
StringBuilder bodyContent = new StringBuilder();
string fileName = "myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
}
catch(Exception ex)
{
Console.WriteLine(String.Format("{0} # {1}", "Exception while reading the file: " + ex.InnerException.Message, DateTime.Now));
throw ex;
}
Thanks to the post from #Sreekanth Gundlapally I have managed to fix my issues. I have mostly drawn on from the answer provided by #Sreekanth Gundlapally but there is one important bit missing. The string fileName should include any subfolders that the resource file is within in the Class Library Project, for example in my case the folder was named 'Resources' so the code should look like this:
string fileName = #"Resources/myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
I have also cleaned and rebuilt solution after which it all worked a charm.
Also a side note, anyone trying this and getting funny characters make sure your file's encoding is set to UTF-8 as this is the default encoding used by StreamReader, otherwise your file content may not be read correctly if it contains signs such as apostrophe.

Checking if resource file exists

I have an image file in my project's folder in visual studio and it is set to build action "resource" so it is included in my exe file.
I can link to this file in xaml no problem, for example <Image Source="images/myimage.png"> and it works.
But if I try to check the existence of the file, with File.exists("images/myimage.png") it always returns false. What am i doing wrong here?
If you do not want to have it bundled to the output folder additionally - you do not have to do anything. It is build into your exe, not need to check. Would always be true.
Okay, I understand because you dynamically build the name of your embedded resource you want to check it.
See here: WPF - check resource exists without structured exception handling
They basically check against Assembly.GetExecutingAssembly().GetManifestResourceNames()
You can use that as a starting point. But note that the resource name is not images/myimage.png but constructed from your namespace like YourApp.images.myimage.png. You might like to take a look at the contents of the built resourceNames array from that answer.
Xamarin.Forms
From a working code, checks if auto-generated filename exists in embedded resources in the shared project (as described here https://developer.xamarin.com/guides/xamarin-forms/user-interface/images/#Embedded_Images)
var assembly = typeof(App).GetTypeInfo().Assembly;
var AssemblyName = assembly.GetName().Name;
var generatedFilename = AssemblyName+".Images.flags.flag_" + item.CountryCode?.ToLower() + #".png";
bool found = false;
foreach (var res in assembly.GetManifestResourceNames())
{
if (res == generatedFilename)
{
found = true;
break;
}
}
if (found)
UseGeneratedFilename();
else
UseSomeOtherPlaceholderImage;
Have you set the "Copy to the Output" property to "Always"? And make sure that you use the correct path. The path of your executing assembly can be detected by using following code:
private string GetExecutingAssemblyPath()
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
Cheers.

Loading files in default Internet browser programmatically

I used this to load a file (html_file.html) from Resources
//string myFile = "C:\\Users\\...\\Resources\\html_file.html"; // this works
var myFile = Path.GetFullPath("html_file.html"); // this doesn't works
//myFile = myFile.ToString();
//myFile = myFile.Replace(#"\", #"\\");
//MessageBox.Show(myFile);
try
{
Process.Start(myFile);
}
catch (Win32Exception noBrowser)
{
if (noBrowser.ErrorCode == -2147467259)
MessageBox.Show(noBrowser.Message);
}
catch (System.Exception other)
{
MessageBox.Show(other.Message);
}
Can someone tell me what's wrong?
EDIT : This works
Build Action = Embedded Resource and Copy to Output Directory = Copy always
string myFile = #".\Resources\html_file.html";
but I still need to have the path Resources with the file. Is there any way to have the 'html_file' inside my .EXE file?
Quite obviously it cannot find the file in the current directory. Make sure the following are correct:
The file is included in your project and its Copy to Output Directory property is set to Copy always or Copy if newer.
Use Application.StartupPath to make sure you are pointing to correct directory, so the first line would become:
Code:
var myFile = Path.Combine(Application.StartupPath, "html_file.html");
In the first method you specify the exact path to your file.
In the second one you ask the framework to create a fullpath.
The framework need to start from somewhere and it choose to start from your current directory but the file is not present there

Bundle a folder with a .Net application

How can I bundle a folder with a one click application and reference those files/folders after?
Seems rather simple but I just can't figure out how.
As in, I had the file index.html in the folder UI and I wanted to package that with the application, then I want to get the stream for that file with the string "/UI/index.html" but instead of just index.html, an entire website.
Add the folder to your VS Project, right-click on it and select "embed as resource". That will make the files in the folder be embedded in the .NET assembly. To get the file contents in your program, you can use something like this:
public class ReadResource
{
public string ReadInEmbeddedFile (string filename) {
// assuming this class is in the same assembly as the resource folder
var assembly = typeof(ReadResource).Assembly;
// get the list of all embedded files as string array
string[] res = assembly.GetManifestResourceNames ();
var file = res.Where (r => r.EndsWith(filename)).FirstOrDefault ();
var stream = assembly.GetManifestResourceStream (file);
string file_content = new StreamReader(stream).ReadToEnd ();
return file_content;
}
}
In the above function I assume your files a text/html files; if not, you can change it not to return string but byte[], and use a binary stream reader for that.
I also select the files by file.EndsWith() which is enough for my needs; if your folder has a deep nested structure you need to modify that code to parse for folder levels.
Perhaps there is a better way, but given the content is not too large you can embed binaries directly into your program as a base64 string. In this case it would need to be an archive of the folder. You would also need to embed the dll used for unzipping that archive (If I understood correctly you want to have single .exe and nothing more).
Here is a short example
// create base64 strings prior to deployment
string unzipDll = Convert.ToBase64String(File.ReadAllBytes("Ionic.Zip.dll"));
string archive = Convert.ToBase64String(File.ReadAllBytes("archive.zip"));
string unzipDll = "base64string";
string archive = "probablyaverylongbase64string";
File.WriteAllBytes("Ionic.zip.dll", Convert.FromBase64String(unzipDll));
File.WriteAllBytes("archive.zip", Convert.FromBase64String(archive);
Ionic.Zip.ZipFile archive = new Ionic.Zip.ZipFile(archiveFile);
archive.ExtractAll("/destination");
The unzipping library is DotNetZip. It's nice because you need just a single dll. http://dotnetzip.codeplex.com/downloads/get/258012
Edit:
Come to think of it, as long as you write the Ionic.dll to the working directory of the .exe you shouldn't need to use the dynamic dll loading so I removed that part to simplify the answer (it would still need to be written before you reach the method it is in though).

problem with opening a file in C#

What am I doing wrong in the following code?
public string ReadFromFile(string text)
{
string toReturn = "";
System.IO.FileStream stream = new System.IO.FileStream(text, System.IO.FileMode.Open);
System.IO.StreamReader reader = new System.IO.StreamReader(text);
toReturn = reader.ReadToEnd();
stream.Close();
return toReturn;
}
I put a text.txt file inside my bin\Debug folder and for some reason, each time when I enter this file name ("text.txt") I am getting an exception of System.IO.FileNotFoundException.
It is not safe to assume that the current working directory is identical to the directory in which your binary is residing. You can usually use code like the following to refer to the directory of your application:
string applicationDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
string filename = System.IO.Path.Combine(applicationDirectory, text);
This may or may not be a solution for your given problem. On a sidenote, text is not really a decent variable name for a filename.
If I want to open a file that is always in a folder relative to the application's startup path, I use:
Application.StartupPath
to simply get the startuppath, then I append the rest of the path (subfolders and or file name).
On a side note: in real life (i.e. in the end user's configuration) the location of a file you need to read is seldom relative to the applications startup path. Applications are usually installed in the Program Files folder, application data is stored elsewhere.
File.ReadAllText(path) does the same thing as your code. I would suggest using rooted path like "c:......\text.txt" instead of the relative path. The current directory is not necessarily set to your app's home directory.
You can use Process Monitor (successor to FileMon) to find out exactly what file your application tries to read.
My suggestions:
public string ReadFromFile(string fileName)
{
using(System.IO.FileStream stream = new System.IO.FileStream(fileName, System.IO.FileMode.Open))
using(System.IO.StreamReader reader = new System.IO.StreamReader(stream))
{
return = reader.ReadToEnd();
}
}
or even
string text = File.OpenText(fileName).ReadToEnd();
You can also check is file exists:
if(File.Exists(fileName))
{
// do something...
}
At last - maybe your text.txt file is open by other process and it can't be read at this moment.

Categories