Je suis à peu près sûr que ce n'est pas un doublon, alors ne m'attendez pas une minute.
Comment puis-je programmer (C #) compresser un fichier (sous Windows) sans utiliser de bibliothèques tierces? J'ai besoin d'un appel Windows natif ou quelque chose comme ça; Je n'aime vraiment pas l'idée de démarrer un processus, mais je le ferai si je le dois absolument. Un appel PInovke serait beaucoup mieux.
En cas d'échec, laissez-moi vous dire ce que j'essaie vraiment d'accomplir: j'ai besoin de la possibilité de permettre à un utilisateur de télécharger une collection de documents en une seule requête. Des idées sur la façon d'accomplir ceci?
Utilisez-vous .NET 3.5? Vous pouvez utiliser la classe ZipPackage
et les classes associées. Cela ne se limite pas à zipper une liste de fichiers car il faut un type MIME pour chaque fichier ajouté. Cela pourrait faire ce que vous voulez.
J'utilise actuellement ces classes pour un problème similaire afin d'archiver plusieurs fichiers liés dans un seul fichier pour le téléchargement. Nous utilisons une extension de fichier pour associer le fichier téléchargé à notre application de bureau. Un petit problème que nous avons rencontré est qu’il n’est pas possible d’utiliser un outil tiers tel que 7-Zip pour créer les fichiers Zip, car le code côté client ne peut pas l’ouvrir. ZipPackage ajoute un fichier caché décrivant le type de contenu de chaque fichier de composant et ne peut pas ouvrir un fichier Zip si ce fichier de type de contenu est manquant.
Comment puis-je programmer (C #) Zip un fichier (sous Windows) sans utiliser des bibliothèques tierces?
Si vous utilisez le Framework 4.5+, il existe maintenant les classes ZipArchive et ZipFile .
using (ZipArchive Zip = ZipFile.Open("test.Zip", ZipArchiveMode.Create))
{
Zip.CreateEntryFromFile(@"c:\something.txt", "data/path/something.txt");
}
Vous devez ajouter des références à:
Pour le ciblage .NET Core net46, vous devez ajouter des dépendances pour
Exemple project.json:
"dependencies": {
"System.IO.Compression": "4.1.0",
"System.IO.Compression.ZipFile": "4.0.1"
},
"frameworks": {
"net46": {}
}
Pour .NET Core 2.0, il suffit d'ajouter une simple instruction using:
J'étais dans la même situation, souhaitant .NET au lieu d'une bibliothèque tierce. En tant qu'autre affiche mentionnée ci-dessus, il ne suffit pas d'utiliser la classe ZipPackage (introduite dans .NET 3.5). Un fichier supplémentaire DOIT être inclus dans l'archive pour que le ZipPackage fonctionne. Si ce fichier est ajouté, le package Zip résultant peut être ouvert directement à partir de l'Explorateur Windows - aucun problème.
Tout ce que vous avez à faire est d’ajouter le fichier [Content_Types] .xml à la racine de l’archive avec un nœud "Par défaut" pour chaque extension de fichier à inclure. Une fois ajouté, je pouvais parcourir le package à partir de l'Explorateur Windows ou décompresser par programme et lire son contenu.
Vous trouverez plus d’informations sur le fichier .xml [Content_Types] à l’adresse suivante: http://msdn.Microsoft.com/en-us/magazine/cc163372.aspx
Voici un exemple du fichier [Content_Types] .xml (qui doit être nommé exactement):
<?xml version="1.0" encoding="utf-8" ?>
<Types xmlns=
"http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="xml" ContentType="text/xml" />
<Default Extension="htm" ContentType="text/html" />
<Default Extension="html" ContentType="text/html" />
<Default Extension="rels" ContentType=
"application/vnd.openxmlformats-package.relationships+xml" />
<Default Extension="jpg" ContentType="image/jpeg" />
<Default Extension="png" ContentType="image/png" />
<Default Extension="css" ContentType="text/css" />
</Types>
Et le C # pour créer un fichier Zip:
var zipFilePath = "c:\\myfile.Zip";
var tempFolderPath = "c:\\unzipped";
using (Package package = ZipPackage.Open(zipFilePath, FileMode.Open, FileAccess.Read))
{
foreach (PackagePart part in package.GetParts())
{
var target = Path.GetFullPath(Path.Combine(tempFolderPath, part.Uri.OriginalString.TrimStart('/')));
var targetDir = target.Remove(target.LastIndexOf('\\'));
if (!Directory.Exists(targetDir))
Directory.CreateDirectory(targetDir);
using (Stream source = part.GetStream(FileMode.Open, FileAccess.Read))
{
source.CopyTo(File.OpenWrite(target));
}
}
}
Remarque:
private static string CompressFile(string sourceFileName)
{
using (ZipArchive archive = ZipFile.Open(Path.ChangeExtension(sourceFileName, ".Zip"), ZipArchiveMode.Create))
{
archive.CreateEntryFromFile(sourceFileName, Path.GetFileName(sourceFileName));
}
return Path.ChangeExtension(sourceFileName, ".Zip");
}
Pour une application .NET 2.0, j'ai utilisé SharpZipLib . Facile à utiliser et open source.
Basé sur la réponse de Simon McKenzie à cette question , je suggérerais d'utiliser une paire de méthodes comme celle-ci:
public static void ZipFolder(string sourceFolder, string zipFile)
{
if (!System.IO.Directory.Exists(sourceFolder))
throw new ArgumentException("sourceDirectory");
byte[] zipHeader = new byte[] { 80, 75, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
using (System.IO.FileStream fs = System.IO.File.Create(zipFile))
{
fs.Write(zipHeader, 0, zipHeader.Length);
}
dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
dynamic source = shellApplication.NameSpace(sourceFolder);
dynamic destination = shellApplication.NameSpace(zipFile);
destination.CopyHere(source.Items(), 20);
}
public static void UnzipFile(string zipFile, string targetFolder)
{
if (!System.IO.Directory.Exists(targetFolder))
System.IO.Directory.CreateDirectory(targetFolder);
dynamic shellApplication = Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
dynamic compressedFolderContents = shellApplication.NameSpace(zipFile).Items;
dynamic destinationFolder = shellApplication.NameSpace(targetFolder);
destinationFolder.CopyHere(compressedFolderContents);
}
}
On dirait que Windows pourrait vous laisser faire ceci ...
Malheureusement, je ne pense pas que vous allez commencer à mettre en place un processus séparé à moins de passer à un composant tiers.
Ajoutez ces 4 fonctions à votre projet:
public const long BUFFER_SIZE = 4096;
public static void AddFileToZip(string zipFilename, string fileToAdd)
{
using (Package Zip = global::System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate))
{
string destFilename = ".\\" + Path.GetFileName(fileToAdd);
Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
if (Zip.PartExists(uri))
{
Zip.DeletePart(uri);
}
PackagePart part = Zip.CreatePart(uri, "", CompressionOption.Normal);
using (FileStream fileStream = new FileStream(fileToAdd, FileMode.Open, FileAccess.Read))
{
using (Stream dest = part.GetStream())
{
CopyStream(fileStream, dest);
}
}
}
}
public static void CopyStream(global::System.IO.FileStream inputStream, global::System.IO.Stream outputStream)
{
long bufferSize = inputStream.Length < BUFFER_SIZE ? inputStream.Length : BUFFER_SIZE;
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
long bytesWritten = 0;
while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) != 0)
{
outputStream.Write(buffer, 0, bytesRead);
bytesWritten += bytesRead;
}
}
public static void RemoveFileFromZip(string zipFilename, string fileToRemove)
{
using (Package Zip = global::System.IO.Packaging.Package.Open(zipFilename, FileMode.OpenOrCreate))
{
string destFilename = ".\\" + fileToRemove;
Uri uri = PackUriHelper.CreatePartUri(new Uri(destFilename, UriKind.Relative));
if (Zip.PartExists(uri))
{
Zip.DeletePart(uri);
}
}
}
public static void Remove_Content_Types_FromZip(string zipFileName)
{
string contents;
using (ZipFile zipFile = new ZipFile(File.Open(zipFileName, FileMode.Open)))
{
/*
ZipEntry startPartEntry = zipFile.GetEntry("[Content_Types].xml");
using (StreamReader reader = new StreamReader(zipFile.GetInputStream(startPartEntry)))
{
contents = reader.ReadToEnd();
}
XElement contentTypes = XElement.Parse(contents);
XNamespace xs = contentTypes.GetDefaultNamespace();
XElement newDefExt = new XElement(xs + "Default", new XAttribute("Extension", "sab"), new XAttribute("ContentType", @"application/binary; modeler=Acis; version=18.0.2application/binary; modeler=Acis; version=18.0.2"));
contentTypes.Add(newDefExt);
contentTypes.Save("[Content_Types].xml");
zipFile.BeginUpdate();
zipFile.Add("[Content_Types].xml");
zipFile.CommitUpdate();
File.Delete("[Content_Types].xml");
*/
zipFile.BeginUpdate();
try
{
zipFile.Delete("[Content_Types].xml");
zipFile.CommitUpdate();
}
catch{}
}
}
Et utilisez-les comme ceci:
foreach (string f in UnitZipList)
{
AddFileToZip(zipFile, f);
System.IO.File.Delete(f);
}
Remove_Content_Types_FromZip(zipFile);