Ioniczip packed files gets corrupted and filenames missplaced - c#

Im having some trouble with IonicZip corrupting the files im packing down with it. At first i thought it was because of the file names, but i have now discovered that this is not the case.
Heres the code i use to pack down things
using (ZipFile pack = new ZipFile())
{
pack.AddProgress += (s, eventArgs) =>
{
if (eventArgs.EventType == ZipProgressEventType.Adding_AfterAddEntry)
{
Regex pattern = new Regex("[(]|[)]|[']|[[]|[]]|[+]");
eventArgs.CurrentEntry.FileName = pattern.Replace(eventArgs.CurrentEntry.FileName, "");
}
};
pack.AddDirectory(defPackageCreationPath + "\\installfiles", "");
pack.Save(outputPath + "\\package.mpp");
}
I used Regex to remove the shown characters from the filenames of the files being packed, as i thought it was because of the filenames they got corrupted somehow. But it is not.
Heres an example. I can pack down this file without problems
[Forge]FurnitureModv2.9.2(FULL).zip
However! If i pack the same file down with a lot of other files, everything screws up..
Take a look at this screenshot of the source folder, where im taking the files from and packing them with the above code, and the extracted folder to the right:
Notice how the file sizes from the source directory doesn't match with what is extracted? Well take a look at the sizes again.. The filenames are not matching those of the source! The file i mentioned before [Forge]FurnitureModv2.9.2(FULL).zip, which is now called ForgeFurnitureModv2.9.2FULL.zip and has gone from 467KB down to 51KB, and if i try to open it, im being told it is corrupted.. But take a look at the TooMuchTNT v2.5.zip file.. This files size is 467KB as the other file was from source, and if i open this file up i get the contents that should have been in [Forge]FurnitureModv2.9.2(FULL).zip !
So all in all i have two problems:
being that the file names doesnt match their contents from source folder
some files gets corrupted, however if i pack a file that gets corrupted without any other file it works fine, and it does not get corrupted.
Can you assist ? Maybe im packing the files wrongly ?

Related

Editing XPS Print Spool Files(.SPL Extension) in C# (Saving as Zip Problem)

When someone print a document(with XPS printing path) I want to pause print job and edit SPL(which zipped XPS format) file.
If I edit the file with 7zip and save. If I resume the job that document printing without any problem.
If I open the SPL file with System.IO.Compression.ZipFile class or DotNetZip library or SevenZipSharp library and extract a file from SPL file & remove that filefrom SPL file and add that file again to SPL file it generates perfectly fine zip container. I compared the original SPL file and edited SPL file with 7zip, zipinfo, winrar tools and I didn't see any difference. All files in the container are exactly same. I also checked CRCs.
When I'm opening,editing and saving the zipfile I'm not changing anything about compression method, compression level and etc. As I said two zip files looks like exactly same but If I calculate CRCs of original and edited SPL files they are not same.
After I edited(just extracting a page file, deleting it from container and adding it again to container) If I try to resume print job I see an error in event viewer about PrintProcessor and I can't print it.
I can't figure out what's changing after I edit the file(not changing anything in container). I'm going crazy.
Is there any specification about the Zip format of SPL files?
Problem solves If I use "ZipPackage" class.
using (var pack = ZipPackage.Open(xpsFileName, FileMode.Open, FileAccess.ReadWrite))
{
foreach (var part in pack.GetParts()) if (part.Uri.OriginalString.EndsWith(".fpage"))
{
using (var file = part.GetStream(FileMode.Open, FileAccess.ReadWrite))
{
var page = ProcessPage(XElement.Load(file));
file.Position = 0;
page.Save(file);
file.SetLength(file.Position);
}
}
}

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.

C# saving a file path longer than 260 characters in Windows

I have found some questions here asking the same thing, however the answers have not worked for me. I have a path to another machine on the network where I store files in the following format;
\\machinename\share
We have paths longer than 260 characters. It does not allow me to save these paths when I use this code;
private static void CreateDirectories(string totalPath)
{
var file = new FileInfo(totalPath);
if (file.Directory != null && !file.Directory.Exists)
file.Directory.Create();
}
I have tried using the following notations in the 'totalPath' parameter which don't work if I try to navigate to them in file explorer;
\\?\machinename\share
\\?\UNC\machinename\share
Am I using these paths correctly? Neither of these manage to navigate to the share in file explorer. Is there any other way I can save a file with a path that is longer than 260 characters using C# on windows?
Thanks for any pointers.

Include source code for library in that library

I've a plugin based web app that allows an administrator to assign various small pieces of functionality (the actual functionality is unimportant here) to users.
This functionality is configurable and an administrator having an understanding of the plugins is important. The administrator is technical enough to be able to read the very simple source code for these plugins. (Mostly just arithmetic).
I'm aware there are a couple of questions already about accessing source code from within a DLL built from that source:
How to include source code in dll? for example.
I've played with getting the .cs files into a /Resources folder. However doing this with a pre-build event obviously don't include these files in the project. So VS never copies them and I'm unable to access them on the Resources object.
Is there a way to reference the source for a particular class... from the same assembly that I'm missing? Or alternatively a way to extract COMPLETE source from the pdb for that assembly? I'm quite happy to deploy detailed PDB files. There's no security risk for this portion of the solution.
As I've access to the source code, I don't want to go about decompiling it to display it. This seems wasteful and overly complicated.
The source code isn't included in the DLLs, and it isn't in the PDBs either (PDBs only contain a link between the addresses in the DLL and the corresponding lines of code in the sources, as well as other trivia like variable names).
A pre-build event is a possible solution - just make sure that it produces a single file that's included in the project. A simple zip archive should work well enough, and it's easy to decompress when you need to access the source. Text compresses very well, so it might make sense to compress it anyway. If you don't want to use zip, anything else will do fine as well - an XML file, for example. It might even give you the benefit of using something like Roslyn to provide syntax highlighting with all the necessary context.
Decompilation isn't necessarily a terrible approach. You're trading memory for CPU, basically. You'll lose comments, but that shouldn't be a problem if your code is very simple. Method arguments keep their names, but locals don't - you'd need the PDBs for that, which is a massive overkill. It actually does depend a lot on the kind of calculations you're doing. For most cases, it probably isn't the best solution, though.
A bit roundabout way of handling this would be a multi-file T4 template. Basically, you'd produce as many files as there are source code files, and have them be embedded resources. I'm not sure how simple this is, and I'm sure not going to include the code :D
Another (a bit weird) option is to use file links. Simply have the source code files in the project as usual, but also make a separate folder where the same files will be added using "Add as link". The content will be shared with the actual source code, but you can specify a different build action - namely, Embedded Resource. This requires a (tiny) bit of manual work when adding or moving files, but it's relatively simple. If needed, this could also be automated, though that sounds like an overkill.
The cleanest option I can think of is adding a new build action - Compile + Embed. This requires you to add a build target file to your project, but that's actually quite simple. The target file is just an XML file, and then you just manually edit your SLN/CSPROJ file to include that target in the build, and you're good to go. The tricky part is that you'll also need to force the Microsoft.CSharp.Core.target to use your Compile + Embed action to be used as both the source code and the embedded resource. This is of course easily done by manually changing that target file, but that's a terrible way of handling that. I'm not sure what the best way of doing that is, though. Maybe there's a way to redefine #(Compile) to mean #(Compile;MyCompileAndEmbed)? I know it's possible with the usual property groups, but I'm not sure if something like this can be done with the "lists".
Taking from #Luaan's suggestion of using a pre-build step to create a single Zipped folder I created a basic console app to package the source files into a zip file at a specific location.
static void Main(string[] args)
{
Console.WriteLine("Takes a folder of .cs files and flattens and compacts them into a .zip." +
"Arg 1 : Source Folder to be resursively searched" +
"Arg 2 : Destination zip file" +
"Arg 3 : Semicolon List of folders to ignore");
if (args[0] == null || args[1] == null)
{
Console.Write("Args 1 or 2 missing");
return;
};
string SourcePath = args[0];
string ZipDestination = args[1];
List<String> ignoreFolders = new List<string>();
if (args[2] != null)
{
ignoreFolders = args[2].Split(';').ToList();
}
var files = DirSearch(SourcePath, "*.cs", ignoreFolders);
Console.WriteLine($"{files.Count} files found to zip");
if (File.Exists(ZipDestination))
{
Console.WriteLine("Destination exists. Deleting zip file first");
File.Delete(ZipDestination);
}
int zippedCount = 0;
using (FileStream zipToOpen = new FileStream(ZipDestination, FileMode.OpenOrCreate))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
{
foreach (var filePath in files)
{
Console.WriteLine($"Writing {Path.GetFileName(filePath)} to zip {Path.GetFileName(ZipDestination)}");
archive.CreateEntryFromFile(filePath, Path.GetFileName(filePath));
zippedCount++;
}
}
}
Console.WriteLine($"Zipped {zippedCount} files;");
}
static List<String> DirSearch(string sDir, string filePattern, List<String> excludeDirectories)
{
List<String> filePaths = new List<string>();
foreach (string d in Directory.GetDirectories(sDir))
{
if (excludeDirectories.Any(ed => ed.ToLower() == d.ToLower()))
{
continue;
}
foreach (string f in Directory.GetFiles(d, filePattern))
{
filePaths.Add(f);
}
filePaths.AddRange(DirSearch(d, filePattern, excludeDirectories));
}
return filePaths;
}
Takes 3 parameters for source dir, output zip file and a ";" separated list of paths to exclude. I've just built this as a binary. Committed it to source control for simplicity and included it in the pre-build for projects I want the source for.
No error checking really and I'm certain it will fail for missing args. But if anyone wants it. Here it is! Again Thanks to #Luaan for clarifying PDBs aren't all that useful!

SharpZipLib - adding folders/directories to a zip archive

From examples, I've got a pretty good grasp over how to extract a zip file.
In nearly every example, the method of identifying when a ZipEntry is a directory is as follows
string directoryName = Path.GetDirectoryName(theEntry.Name);
string fileName = Path.GetFileName(theEntry.Name);
if (directoryName.Length > 0)
Directory.CreateDirectory(Path.Combine(destinationDirectory, directoryName));
if (fileName != String.Empty)
{
//read data and write to file
}
Now is is fine and all (directory encountered, create it), directory is available when the file is extracted.
I can add files to a zip fine, but how do I add folders? I understand I'll be looping through the directories, adding the files encountered (and their ZipEntry.Name property is populated properly), but how do I add a ZipEntry to the archive and instruct the ZipOutputStream that it is a directory?
ZipFile.AddDirectory does what you want. Small sample code here.

Categories