Changing content in Embedded Resources file - c#

I want to change the content of a file loaded as a Stream from an embedded resource.
The following code gets the file:
Stream theFile = Assembly.GetExecutingAssembly().GetManifestResourceStream("_3LinksFourmTool.Resources.fourmlinks.txt");
I created a method that takes a string of text that is present in the Stream provided. The string is rewritten to the Stream with the new content.
public static void WriteNewTextToFile(string text, Stream theFile)
{
string fileText = GetAllTextFromFile(theFile);
ArrayList fileLIst = populateListFromText(fileText);
using (StreamWriter fileWriter = new StreamWriter(theFile))
{
fileWriter.Write("");
for (int i = 0; i < fileLIst.Count; i++)
{
fileWriter.WriteLine(fileLIst[i].ToString());
}
}
}
The above code throws the System.ArgumentException.
Does this exception have anything to do with the text file being an Embedded Resource?
How can I modify this file without the System.ArgumentException being thrown?

Resources cannot be modified at runtime, in part because the executable is executing at the time, and no writes could be made to it. you can use an external binary editor to modify them, if all you have is the assembly, or you can recompile your project with the altered file. In most app platforms, in order to open a resource for write or execute, you must extract the file from the binary first, and then perform your ops on it. you can;t put it back however.
here are some links on how to manipluate resources at design/compile time:
http://msdn.microsoft.com/en-us/library/7k989cfy%28v=vs.90%29.aspx
http://msdn.microsoft.com/en-us/library/cd818wbk%28v=vs.100%29.aspx
in this case, have you considered using Settings, instead of resources? They can be saved at runtime, so if you just need text value stuff, that should work well for you.

Related

How to read a file into an array on Xamerin in IOS app using StreamReader (or some other alternative)

I am trying to do what I thought would be a simple task, but can't figure it out.
I have created a new Xamerin Forms project (using .net standard, as sharing strategy,) and it looks like this:
I created a text file and I want to read it into an array so I can use it in my app.
I added the text file to my project (by adding it to the top project, which doesn't have an OS associated with it), here:
In my app I have the following code:
InitializeComponent ();
//Define our array variable
string[] quotations = new string[10];
//Read the text from text file and populate array
StreamReader SR = new StreamReader(#"Quotations.txt");
for (int i = 0; i < 9; i++)
{
quotations[i] = SR.ReadLine();
}
Quote.Text = quotations[0];
//Close text file
SR.Close();
...
I have checked the properties for the file, and set them to 'build action: embedded resource', in the top project.
(I haven't added the file into the individual OS projects...)
When I run my application, on IOS it generates an exception, and exits the app almost as soon as it started:
Unhandled Exception: System.IO.FileNotFoundException:
How can I attach a file to my project, and read the contents into an array , on IOS?
Thanks
new StreamReader(#"Quotations.txt"); loads a file from the file system, but your data isn't in the file system - it is embedded in the assembly.
Embedded resources need to be accessed in a special way - in particular via yourAssembly.GetManifestResourceStream(resourceName). Note that the embedded name might not be quite what you expect, so the best thing to do is to (as a quick test) use yourAssembly.GetManifestResourceNames() and write out the names that are embedded. That'll tell you the one to actually include as resourceName. Once you have the Stream, you can use a new StreamReader(theResourceStream) on it.
Note: the easiest way to get yourAssembly is something like typeof(SomeTypeInYourAssembly).Assembly.

Using File.ReadAllLines from embedded text file

I have been applying what I have learned so far in Bob Tabors absolute beginners series and I wrote a small console word game for my daughter that requires me to generate a random 5 letter word.
I was previously using File.ReadAllLines(path) to generate a string array from a text file (wordlist.txt) on my system and Random.next to generate the index I would pull from the array.
I learned from some posts here how to embed the file as a resource but now I am unable to find the syntax to point to it (path). Or do I have to access it differently now that it is embedded?
Thanks in advance
Without a good, minimal, complete code example it is impossible to offer specific advice.
However, the basic issue is this: when you embed a file as a resource, it is no longer a file. That is, the original file still exists, but the resource itself is not a file in any way. It is stored as some specific kind of data in your assembly; resources embedded from file sources generally wind up as binary data objects.
How to use this data depends on what you mean by "embed". There are actually two common ways to store resources in a C# program: you can use the "Resources" object in the project, which exposes the resource via the project's ...Properties.Resources class (which in turn uses the ResourceManager class in .NET). Or you can simply add the file to the project itself, and select the "Embedded Resource" build option.
If you are using the "Resources" designer, then there are a couple of different ways you might have added the file. One is to use the "New Text File..." option, which allows you to essentially copy/paste or type new text into a resource. This is exposed in code as a string property on the Properties.Resources object. The same thing will happen if you add the resource using the "Existing File..." option and select a file that Visual Studio recognizes as a text file.
Otherwise, the file will be included as a byte[] object exposed by a property in the Properties.Resources class.
If you have used the "Embedded Resource" build option instead of the "Resources" designer, then your data will be available by calling Assembly.GetManifestResourceStream(string) method, which returns a Stream object. This can be wrapped in StreamReader to allow it to be read line-by-line.
Direct replacements for the File.ReadAllLines(string) approach would look something like the following…
Using "Embedded Resource":
string[] ReadAllResourceLines(string resourceName)
{
using (Stream stream = Assembly.GetEntryAssembly()
.GetManifestResourceStream(resourceName))
using (StreamReader reader = new StreamReader(stream))
{
return EnumerateLines(reader).ToArray();
}
}
IEnumerable<string> EnumerateLines(TextReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
Using Properties.Resources:
You can do something similar when using the Properties.Resources class. It looks almost identical:
string[] ReadAllResourceLines(string resourceText)
{
using (StringReader reader = new StringReader(resourceText))
{
return EnumerateLines(reader).ToArray();
}
}
called like string[] allLines = ReadAllResourceLines(Properties.Resources.MyTextFile);, where MyTextFile is the property name for the resource you added in the designer (i.e. the string you pass in that second example is the text of the file itself, not the name of the resource).
If you added an existing file that Visual Studio didn't recognize as a text file, then the property type will be byte[] instead of string and you'll need yet another slightly different approach:
string[] ReadAllResourceLines(byte[] resourceData)
{
using (Stream stream = new MemoryStream(resourceData))
using (StreamReader reader = new StreamReader(stream))
{
return EnumerateLines(reader).ToArray();
}
}
Note that in all three examples, the key is that the data winds up wrapped in a TextReader implementation, which is then used to read each line individually, to populate an array. These all use the same EnumerateLines() helper method I show above.
Of course, now that you see how the data can be retrieved, you can adapt that to use the data in a variety of other ways, in case for example you don't really want or need the text represented as an array of string objects.
If you are using The Resource file and added a text file you could use
string text=Properties.Resources.<ResourceName>
here Resources is default Resource for your project .If you have added a custom Resource File you can use its name instead of Properties.Resources
if your content is a file then it is represented as a byte.In your case for simple Text it will be an string if you have included a Text File.
for any other file you can use the syntax for converting content to text(if it is text) as
string text=Encoding.ASCII.GetString(Properties.Resources.<ResourceName>);
if your file has any other encoding (as UTF Unicode ) you can use UTF8 or such classes for that under Encoding

C# Access text file in zip archive

How can I read content of a text file inside a zip archive?
For example I have an archive qwe.zip, and insite it there's a file asd.txt, so how can I read contents of that file?
Is it possible to do without extracting the whole archive? Because it need to be done quick, when user clicks a item in a list, to show description of the archive (it needed for plugin system for another program). So extracting a whole archive isn't the best solution... because it might be few Mb, which will take at least few seconds or even more to extract... while only that single file need to be read.
You could use a library such as SharpZipLib or DotNetZip to unzip the file and fetch the contents of individual files contained inside. This operation could be performed in-memory and you don't need to store the files into a temporary folder.
Unzip to a temp-folder take the file and delete the temp-data
public static void Decompress(string outputDirectory, string zipFile)
{
try
{
if (!File.Exists(zipFile))
throw new FileNotFoundException("Zip file not found.", zipFile);
Package zipPackage = ZipPackage.Open(zipFile, FileMode.Open, FileAccess.Read);
foreach (PackagePart part in zipPackage.GetParts())
{
string targetFile = outputDirectory + "\\" + part.Uri.ToString().TrimStart('/');
using (Stream streamSource = part.GetStream(FileMode.Open, FileAccess.Read))
{
using (Stream streamDestination = File.OpenWrite(targetFile))
{
Byte[] arrBuffer = new byte[10000];
int iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
while (iRead > 0)
{
streamDestination.Write(arrBuffer, 0, iRead);
iRead = streamSource.Read(arrBuffer, 0, arrBuffer.Length);
}
}
}
}
}
catch (Exception)
{
throw;
}
}
Although late in the game and the question is already answered, in hope that this still might be useful for others who find this thread, I would like to add another solution.
Just today I encountered a similar problem when I wanted to check the contents of a ZIP file with C#. Other than NewProger I cannot use a third party library and need to stay within the out-of-the-box .NET classes.
You can use the System.IO.Packaging namespace and use the ZipPackage class. If it is not already included in the assembly, you need to add a reference to WindowsBase.dll.
It seems, however, that this class does not always work with every Zip file. Calling GetParts() may return an empty list although in the QuickWatch window you can find a property called _zipArchive that contains the correct contents.
If this is the case for you, you can use Reflection to get the contents of it.
On geissingert.com you can find a blog article ("Getting a list of files from a ZipPackage") that gives a coding example for this.
SharpZipLib or DotNetZip may still need to get/read the whole .zip file to unzip a file. Actually, there is still method could make you just extract special file from the .zip file without reading the entire .zip file but just reading small segment.
I needed to have insights into Excel files, I did it like so:
using (var zip = ZipFile.Open("ExcelWorkbookWithMacros.xlsm", ZipArchiveMode.Update))
{
var entry = zip.GetEntry("xl/_rels/workbook.xml.rels");
if (entry != null)
{
var tempFile = Path.GetTempFileName();
entry.ExtractToFile(tempFile, true);
var content = File.ReadAllText(tempFile);
[...]
}
}

Deploy an application's xml file with installer or create it on the fly if it does not exist

I am having an xml file like:
<CurrentProject>
// Elements like
// last opened project file to reopen it when app starts
// and more global project independend settings
</CurrentProject>
Now I asked myself wether I should deliver this xml file with above empty elements with the installer for my app or should I create this file on the fly on application start if it does not exist else read the values from it.
Consider also that the user could delete this file and that should my application not prevent from working anymore.
What is better and why?
UPDATE:
What I did felt ok for me so I post my code here :) It just creates the xml + structure on the fly with some security checks...
public ProjectService(IProjectDataProvider provider)
{
_provider = provider;
string applicationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
_projectPath = Path.Combine(applicationPath,#"TBM\Settings.XML");
if (!File.Exists(_projectPath))
{
string dirPath = Path.Combine(applicationPath, #"TBM");
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (var stream = File.Create(_projectPath))
{
XElement projectElement = new XElement("Project");
projectElement.Add(new XElement("DatabasePath"));
projectElement.Save(stream, SaveOptions.DisableFormatting);
}
}
}
In a similar scenario, I recently went for creating the initial file on the fly. The main reason I chose this was the fact that I wasn't depending on this file being there and being valid. As this was a file that's often read from/written to, there's a chance that it could get corrupted (e.g. if the power is lost while the file is being written).
In my code I attempted to open this file for reading and then read the data. If anywhere during these steps I encountered an error, I simply recreated the file with default values and displayed a corresponding message to the user.

How To Write To An Embedded Resource?

I keep getting the error "Stream was not writable" whenever I try to execute the following code. I understand that there's still a reference to the stream in memory, but I don't know how to solve the problem. The two blocks of code are called in sequential order. I think the second one might be a function call or two deeper in the call stack, but I don't think this should matter, since I have "using" statements in the first block that should clean up the streams automatically. I'm sure this is a common task in C#, I just have no idea how to do it...
string s = "";
using (Stream manifestResourceStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("Datafile.txt"))
{
using (StreamReader sr = new StreamReader(manifestResourceStream))
{
s = sr.ReadToEnd();
}
}
...
string s2 = "some text";
using (Stream manifestResourceStream =
Assembly.GetExecutingAssembly().GetManifestResourceStream("Datafile.txt"))
{
using (StreamWriter sw = new StreamWriter(manifestResourceStream))
{
sw.Write(s2);
}
}
Any help will be very much appreciated. Thanks!
Andrew
Embedded resources are compiled into your assembly, you can't edit them.
As stated above, embedded resources are read only. My recommendation, should this be applicable, (say for example your embedded resource was a database file, XML, CSV etc.) would be to extract a blank resource to the same location as the program, and read/write to the extracted resource.
Example Pseudo Code:
if(!Exists(new PhysicalResource())) //Check to see if a physical resource exists.
{
PhysicalResource.Create(); //Extract embedded resource to disk.
}
PhysicalResource pr = new PhysicalResource(); //Create physical resource instance.
pr.Read(); //Read from physical resource.
pr.Write(); //Write to physical resource.
Hope this helps.
Additional:
Your embedded resource may be entirely blank, contain data structure and / or default values.
A bit late, but for descendants=)
About embedded .txt:
Yep, on runtime you couldnt edit embedded because its embedded. You could play a bit with disassembler, but only with outter assemblies, which you gonna load in current context.
There is a hack if you wanna to write to a resource some actual information, before programm starts, and to not keep the data in a separate file.
I used to worked a bit with winCE and compact .Net, where you couldnt allow to store strings at runtime with ResourceManager. I needed some dynamic information, in order to catch dllNotFoundException before it actually throws on start.
So I made embedded txt file, which I filled at the pre-build event.
like this:
cd $(ProjectDir)
dir ..\bin\Debug /a-d /b> assemblylist.txt
here i get files in debug folder
and the reading:
using (var f = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("Market_invent.assemblylist.txt")))
{
str = f.ReadToEnd();
}
So you could proceed all your actions in pre-build event run some exes.
Enjoy! Its very usefull to store some important information and helps avoid redundant actions.

Categories