Extract embedded resources in C# - c#

I have four resource files embedded in my C# executable, 1 python script and 3 perl scripts. I could extract all three perl scripts successfully. But I am not able to extract the python script. I tried so many ways. Could someone please have a look ? Thank you.
public static string ExtractResource(string resourceName)
{
string destFile = "";
//look for the resource name
foreach (string currentResource in System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceNames() )
if (currentResource.LastIndexOf(resourceName) != -1)
{
string subPath = Common_Utilities.GetTempPath() + "SCRIPTS";
bool isExists = System.IO.Directory.Exists(subPath);
if (!isExists)
System.IO.Directory.CreateDirectory(subPath);
string strFile = subPath + "\\" + resourceName;
string path = System.IO.Path.GetDirectoryName(strFile);
string rootName = System.IO.Path.GetFileNameWithoutExtension(strFile);
destFile = path + #"\" + rootName + System.IO.Path.GetExtension(currentResource);
System.IO.Stream fs = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream( currentResource ) ;
byte[] buff = new byte[fs.Length];
fs.Read(buff, 0, (int)fs.Length);
fs.Close();
System.IO.FileStream destStream = new System.IO.FileStream(destFile, FileMode.Create);
destStream.Write(buff, 0, buff.Length);
destStream.Close();
}
return destFile;
// throw new Exception("Resource not found : " + resourceName);
}

Not sure why the Python script can't be extracted.... couple points though:
I would recommend to use Path.Combine() to stick together path and file name - don't do this yourself, too many chances for error!
Since those are (text-based) scripts, you could do the whole copying much simpler:
System.IO.Stream fs = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(currentResource);
string scriptContents = new StreamReader(fs).ReadToEnd();
File.WriteAllText(destFile, scriptContents);
With this approach, you should be easily able to see in debugging whether or not the script is properly loaded from resources. If not - check your resource name etc. (is the script really set to "embedded" resource?). If you have subdirectories for your resources, be aware that the resource name will contain those subdirectories as part of the fully qualified name - but separated by a dot (.), not a backslash like a physical path!

easy way you can mod your code with
Binary files -> File.WriteAllBytes(Path, Properties.Resources.filename);
Text files -> File.WriteAllText(Path, Properties.Resources.filename);

Related

i have to Create Folder in bin-debug and then create and write in text file in it

i wrote this code , it ctreates folder named "Fitness50" each time but the text file is not created.i want to create textfile within this folder and then save values of an arraylist.
so for i have tried this
DirectoryInfo myDir = new DirectoryInfo(#"E:");
ParentFolderName1 = "Fittness50";
myDir.CreateSubdirectory(ParentFolderName1);
myDir = new DirectoryInfo(ParentFolderName1);
ParentFolderName1 = "Fittness50";
myDir.CreateSubdirectory(ParentFolderName1);
FileName1 = "./" + "" + ParentFolderName1 + "" + "/" + "Fittness10" + "" + "" + PopulationID + "" + ".txt";
FileStream fs2 = new FileStream(FileName1, FileMode.Create, FileAccess.Write);
StreamWriter SW2 = new StreamWriter(fs2);
for (i = 0; i < AlTargetData.Count; i++)
{
SW2.WriteLine(AlTargetData[i]);
}
AlTargetData.Clear();
SW2.Close();
fs2.Close();
Well, first of all, / is not the preferred directory separator on Windows, but \ is. Just because / happens to work, there's no reason to use it. Secondly, you're not creating the Fittness10 folder at all, but you're creating Fittness50 twice. And third, you're not writing the file to the folders you create, but to the current working directory ..
Your code (or at least what I understand you want to achieve) can be shortened significantly to this:
string path = #"E:\Fittness50\Fittness10";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
string fileName = Path.Combine(path, String.Format("{0}.txt", PopulationID));
File.WriteAllText(fileName, String.Join(Environment.NewLine, AlTargetData));
Please note that you should not consider writing to bin\debug. There will be no bin\debug on the end-user's machine. If the user installs your application, it will be most probably be installed in the Program Files folder, which your application won't be allowed to write to. Instead, consider writing to a common location, like the ones you can chose from in Environment.GetFolderPath.

StreamWriter to project directory and sub directory?

I'm currently having an issue with my application and I'm starting to think it's just my logic. I can't figure it out even after browsing these forms and MSDN.
I'm trying to use StreamWriter to create a text document in my app directory and create sub folder containing that document. Currently it just keeps dumping the file in my apps exe directory.
string runTimeDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string recipeDirectory = Path.Combine(runTimeDirectory, "Recipes");
if (!Directory.Exists(recipeDirectory))
{
//Recipes directory doesnt exist so create it
Directory.CreateDirectory(recipeDirectory);
}
// Write text to file
using (StreamWriter OutputFile = new StreamWriter(recipeDirectory + RecipeName + #".txt"))
{
Try this:
using (StreamWriter OutputFile = new StreamWriter(
Path.Combine(recipeDirectory, RecipeName + #".txt")))
The reason I think is that your recipeDirectory and RecipeName + #".txt" aren't separated by the backslash, so the file is written to the parent directory instead and named recipeDirectory + RecipeName + #".txt".
As an aside, I would also recommend you pass your RecipeName through a sanitizer function like this in case any name contains characters that can't be used in a file name:
internal static string GetSafeFileName(string fromString)
{
var invalidChars = Path.GetInvalidFileNameChars();
const char ReplacementChar = '_';
return new string(fromString.Select((inputChar) =>
invalidChars.Any((invalidChar) =>
(inputChar == invalidChar)) ? ReplacementChar : inputChar).ToArray());
}

Programmatically Load Embedded Resource File

i recently implemented the following code in order to programatically build a project/exe. In this exe build, i wanted to store a bunch of "actual files" inside of resources, as streams.
Here's how i'm adding the files into the resource file (singular), and then embedding that resource file into the compiler parameters:
List<string> UserFiles = new List<string>();
UserFiles.AddRange(Helpers.GetFilesInFolder(this.txt_Publish_Folder.Text));
string folder = this.txt_Package_Location.Text;
folder = folder + "\\Package_" + DateTime.Now.ToLongTimeString().Replace(":", "_").Replace(".", "_");
Directory.CreateDirectory(folder);
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = true;
parameters.IncludeDebugInformation = true;
parameters.GenerateInMemory = false;
parameters.WarningLevel = 3;
parameters.CompilerOptions = "/optimize";
parameters.OutputAssembly = folder + "\\Install_" + this.txt_AppName.Text + ".exe";
parameters.ReferencedAssemblies.Add("Microsoft.CSharp.dll");
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("System.Data.dll");
parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
parameters.ReferencedAssemblies.Add("System.Xml.dll");
parameters.ReferencedAssemblies.Add("System.Xml.Linq.dll");
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
if (codeProvider.Supports(GeneratorSupport.Resources))
{
string temp = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());
//create temp file first, because we want to append to it so as to have a single resource file with multiple stream entries...
File.WriteAllText(temp, null);
for (int i = 0; i < UserFiles.Count; i++ )
{
byte[] FileBytes = File.ReadAllBytes(UserFiles[i]);
using (FileStream stream = new FileStream(temp, FileMode.Append))
{
using (ResourceWriter writer = new ResourceWriter(stream))
{
writer.AddResource(Path.GetFileName(UserFiles[i]), FileBytes);
}
}
}
parameters.EmbeddedResources.Add(temp);
}
CompilerResults res = codeProvider.CompileAssemblyFromFile(parameters, #"C:\HIDDENPATH\Program.cs");
This works great, doesn't yield any errors, and i can actually get the embedded resource file out in the Console Application i built (the one referenced above as Prorgam.cs) through the code below. The problem i am having however is with "Loading" this resource file into the application assembly / getting its values out somehow... here's the code i have so far to do that:
static void Main(string[] args)
{
Console.WriteLine("Checking for resources... please wait...");
Assembly thisExe;
thisExe = Assembly.GetExecutingAssembly();
List<string> resources = thisExe.GetManifestResourceNames().ToList();
if(resources.Count >= 1)
{
try
{
string baseName = resources[0];
ResourceManager mgr = new ResourceManager(baseName, thisExe);
Console.WriteLine("retrieved manager...");
Console.ReadLine();
ResourceSet set = mgr.GetResourceSet(Thread.CurrentThread.CurrentCulture, true, true);
int count = set.Cast<object>().Count();
Console.WriteLine("Found [" + count.ToString() + "] embedded resources. Would you like to enumerate them?");
ConsoleKeyInfo input = Console.ReadKey();
if (input.Key == ConsoleKey.Y)
{
// Build the string of resources.
foreach (string resource in resources)
Console.WriteLine(resource);
}
}
catch (Exception ex)
{
Console.Write(ex.Message);
Console.ReadLine();
}
}
Console.ReadLine();
}
Whenever i run the built exe, i get the following result:
Checking for resources... please wait...
retrieved manager...
Could not find any resources appropriate for the specified culture or the neutral culture. Make sure "tmpCC59.tmp.resources" was correctly embedded or linked into assembly "Install_testing" at compile time, or that all the satellite assemblies required are loadable and fully signed.
Can someone please tell me why this is happenning? i've tried all different culture sets i could think of and still nothing comes out. Is the problem related to how i'm "Embedding" or how i'm "Loading" ?
Ok folks, so this is what i ended up with, which actually fixed all my problems.
Instead of trying to add "Resource Entries" into a single "Resource File", i'm now adding every file as its own resource, directly from the source file (don't know why i thought making a temp copy of the original and using a stream was necessary but it's not) like this:
for (int i = 0; i < WebAppFiles.Count; i++)
{
parameters.EmbeddedResources.Add(WebAppFiles[i]);
}
Then, when comes time to extract the actual files, instead of trying to load a "set" from a single "resource file", i simply extract the data from each embedded resource, like this:
for (int i = 0; i < resources.Count; i++)
{
Console.WriteLine("Extracting file: " + resources[i] + "...");
Stream stream = thisExe.GetManifestResourceStream(resources[i]);
byte[] bytes = new byte[(int)stream.Length];
stream.Read(bytes, 0, bytes.Length);
File.WriteAllBytes(dir + resources[i], bytes);
}
This new way basically means that you tell the compiler that "these files are necessary for the exe and are embedded", so when you call the "build" command, it actually does all the work for you and reads the files in as byte arrays and embeds those into the executable file.
Then, at the other hand, you simply tell the program that you want to save the embedded resources as files, using their own file names.
Hopefully this helps someone else who is trying to do this... as every other post for this type of question had some over complicated answers that were either incomplete (e.g.: how to embed, but not retrieve) or didn't actually work.

Create a copy of a file like Windows7 usually do

Sometimes, in my app, I would like to create a copy of a file that already exist, but I don't want to test if the file already exist, I want only that a copy of that file be created, like Windows 7 do.
E.g.: A file tips.txt. When my app copy it, another file will be created named tips - copy.txt. After, if necessary, a "copy of a copy" tips - copy - copy.txt.
Is there something that I can do in this situation?
Obs: in this app, I am using .NET 3.5 and WPF.
Obs2: I made this question because I thought already existed something similar in .NET.
You should extract the filename and the extension then do a simple File.Copy with a new formatted name
string fileName = "tips.txt";
string file = Path.GetFileNameWithoutExtension(fileName);
string ext = Path.GetExtension(fileName);
File.Copy(fileName, string.Format("{0} - Copy{1}", file, ext);
things get a bit more complicated if you have a fullpath to copy from
string fileName = "C:\\test\\tips.txt";
string path = Path.GetDirectoryName(fileName);
string file = Path.GetFileNameWithoutExtension(fileName);
string ext = Path.GetExtension(fileName);
File.Copy(fileName, Path.Combine(path, string.Format("{0} - Copy{1}", file, ext));
but if you really want to mimic the behavior of Windows Explorer we should do:
string fileName = "C:\\test\\tips.txt";
string path = Path.GetDirectoryName(fileName);
string file = Path.GetFileNameWithoutExtension(fileName);
string ext = Path.GetExtension(fileName);
if(file.EndsWith(" - Copy")) file = file.Remove(0, file.Length - 7);
string destFile = Path.Combine(path, string.Format("{0} - Copy{1}", file, ext));
int num = 2;
while(File.Exists(destFile))
{
destFile = Path.Combine(path, string.Format("{0} - Copy ({1}){2}", file, num, ext));
num++;
}
File.Copy(fileName, destFile);
If Windows Explorer copies a file that ends with " - Copy", it adds a progressive number to destination file, not another " - Copy".
You should also consider that the string 'Copy' is localized and thus it changes in non-english version of the operating system.
In addition to other answers suggesting the usage of classes in the System.IO namespace if you want to get the exact same semantics as Windows Copy dialog, you could use the IFileOperation COM object. And here's a managed wrapper for it.
Not sure if this is exactly what you mean, but:
string fileName = "tips.txt";
File.Copy(fileName, string.format("{0} - copy", fileName);
Or:
File.Copy(fileName, string.format("{0} - copy{1}",
Path.GetFileNameWithoutExtension(fileName),
Path.GetExtension(fileName));
You can use File.Copy
http://msdn.microsoft.com/en-us/library/9706cfs5.aspx
What about :
public static void CopyFileLikeWin7(string pathIn,string fileName, string pathOut)
{
string potentialFileName = Path.Combine(pathOut,fileName);
if(File.Exists(potentialFileName))
{
CopyFileLikeWin7(pathIn, Path.GetFileNameWithoutExtension(fileName) + "-copy" + Path.GetExtension(fileName), pathOut);
}
else
{
File.Copy(pathIn,potentialFileName);
}
}
How about
string fileName = "tips.txt";
string filenamewithoutext = Path.GetFileNameWithoutExtension(fileName);
string ext = Path.GetExtension(fileName);
File.Copy(fileName, string.format("{0} - Copy{1}", filenamewithoutext, ext);
Ok, do not test. Just copy the file and don't handle exception
try
{
File.Copy("","");
}
finally
{
}
Something like this? I think there is plenty of more simple ways in doing this.
string destination = "";
var fileInfo = new FileInfo(#"c:\temp\tips.txt");
var ext = fileInfo.Extension;
var filename = fileInfo.Name.Remove(fileInfo.Name.Length - 4);
File.Copy(fileInfo.FullName, destination + filename + " - Copy" + ext);
regarding Steve answer ("but if you really want to mimic the behaviour of Windows Explorer we should do:"), that I've found very useful, I have one comment:
The line:
if (file.EndsWith(" - Copy")) file = file.Remove(0, file.Length - 7);
Should be changed to:
if (file.EndsWith(" - Copy")) file = file.Remove(file.LastIndexOf(" - Copy"), file.Length - 7);
,since in case file ends with " - Copy" we loose the file name and remain with only the "Copy"(s).

Zip file using C#

I want to zip one "CSV" file in to Zip file using C#.Net. Below i have written some code for create Zip file , using this code i am able to create zip file but after creating "Data1.zip" file extract manually means extracted file extension should be ".csv" but it is not coming.
FileStream sourceFile = File.OpenRead(#"C:\Users\Rav\Desktop\rData1.csv");
FileStream destFile = File.Create(#"C:\Users\Rav\Desktop\Data1.zip");
GZipStream compStream = new GZipStream(destFile, CompressionMode.Compress,false);
try
{
int theByte = sourceFile.ReadByte();
while (theByte != -1)
{
compStream.WriteByte((byte)theByte);
theByte = sourceFile.ReadByte();
}
}
finally
{
compStream.Dispose();
}
http://msdn.microsoft.com/en-us/library/system.io.compression.gzipstream.aspx
This is gzip compression, and apparently it only compresses a stream, which when decompressed takes the name of the archive without the .gz extension. I don't know if I'm right here though. You might as well experiment with the code from MSDN, see if it works.
I used ZipLib for zip compression. It also supports Bz2, which is a good compression algorithm.
Use ICSharpCode.SharpZipLib(you can download it) and do the following
private void CreateZipFile(string l_sFolderToZip)
{
FastZip z = new FastZip();
z.CreateEmptyDirectories = true;
z.CreateZip(l_sFolderToZip + ".zip", l_sFolderToZip, true, "");
if (Directory.Exists(l_sFolderToZip))
Directory.Delete(l_sFolderToZip, true);
}
private void ExtractFromZip(string l_sFolderToExtract)
{
string l_sZipPath ="ur folder path" + ".zip";
string l_sDestPath = "ur location" + l_sFolderToExtract;
FastZip z = new FastZip();
z.CreateEmptyDirectories = true;
z.ExtractZip(l_sZipPath, l_sDestPath, "");
if (File.Exists(l_sZipPath))
File.Delete(l_sZipPath);
}
Hope it helps...
Use one of these libraries:
http://www.icsharpcode.net/opensource/sharpziplib/
http://dotnetzip.codeplex.com/
I prefer #ziplib, but both are well documented and widely spread.
Since .NET Framework 4.5, you can use the built-in ZipFile class (In the System.IO.Compression namespace).
public void ZipFiles(string[] filePaths, string zipFilePath)
{
ZipArchive zipArchive = ZipFile.Open(zipFilePath, ZipArchiveMode.Create);
foreach (string file in filePaths)
{
zipArchive.CreateEntryFromFile(file, Path.GetFileName(file), CompressionLevel.Optimal);
}
zipArchive.Dispose();
}
Take a look at the FileSelectionManager library here: www.fileselectionmanager.com
First you have to add File Selection Manager DLL to your project
Here is an example for zipping:
class Program
{
static void Main(string[] args)
{
String directory = #"C:\images";
String destinationDiretory = #"c:\zip_files";
String zipFileName = "container.zip";
Boolean recursive = true;
Boolean overWrite = true;
String condition = "Name Contains \"uni\"";
FSM FSManager = new FSM();
/* creates zipped file containing selected files */
FSManager.Zip(directory,recursive,condition,destinationDirectory,zipFileName,overWrite);
Console.WriteLine("Involved Files: {0} - Affected Files: {1} ",
FSManager.InvolvedFiles,
FSManager.AffectedFiles);
foreach(FileInfo file in FSManager.SelectedFiles)
{
Console.WriteLine("{0} - {1} - {2} - {3} - {4} Bytes",
file.DirectoryName,
file.Name,
file.Extension,
file.CreationTime,
file.Length);
}
}
}
Here is an example for unzipping:
class Program
{
static void Main(string[] args)
{
String destinationDiretory = #"c:\zip_files";
String zipFileName = "container.zip";
Boolean unZipWithDirectoryStructure = true;
FSM FSManager = new FSM();
/* Unzips files with or without their directory structure */
FSManager.Unzip(zipFileName,
destinationDirectory,
unZipWithDirectoryStructure);
}
}
Hope it helps.
I use the dll fileselectionmanager to compress and decompress files and folders, it has worked properly in my project. You can see example in your web http://www.fileselectionmanager.com/#Zipping and Unzipping files
and documentation http://www.fileselectionmanager.com/file_selection_manager_documentation

Categories