Search This Blog

Monday, April 30, 2018

Wrapper for SharpZipLib (C# compressing nuget package)

Wrapper I wrote for SharpZipLib:


using System;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.SharpZipLib.Core;

public static class SharpZipLibHelper
{
    //I wrapped the author's samples at https://github.com/icsharpcode/SharpZipLib/wiki/Zip-Samples

    #region Functions

    private static bool _ignore(List<string> excludes, string fileName)
    {
        foreach (var exclude in excludes)
        {
            //ignore a group of files with a given extension if it was specified in the excludes list
            if (exclude.IndexOf("*") > -1)
            {
                var fileExtension = Path.GetExtension(fileName);
                var excludeExtension = Path.GetExtension(exclude);
                if (string.Equals(excludeExtension, fileExtension, StringComparison.InvariantCultureIgnoreCase))
                    return true;
            }
            //ignore a specific file if it was specified in the excludes list
            else
            {
                if (string.Equals(fileName, exclude, StringComparison.InvariantCultureIgnoreCase))
                    return true;
            }
        }

        return false;
    }

    private static void _compressFolder(string path, ZipOutputStream zipStream, int folderOffset, List<string> excludes = null)
    {
        var files = Directory.GetFiles(path);

        foreach (string filename in files)
        {
            FileInfo fi = new FileInfo(filename);

            if (excludes == null) excludes = new List<string>();
            if (_ignore(excludes, fi.Name)) continue;

            string entryName = filename.Substring(folderOffset); // Makes the name in zip based on the folder
            entryName = ZipEntry.CleanName(entryName); // Removes drive from name and fixes slash direction
            ZipEntry newEntry = new ZipEntry(entryName);
            newEntry.DateTime = fi.LastWriteTime; // Note the zip format stores 2 second granularity

            // Specifying the AESKeySize triggers AES encryption. Allowable values are 0 (off), 128 or 256.
            // A password on the ZipOutputStream is required if using AES.
            //   newEntry.AESKeySize = 256;

            // To permit the zip to be unpacked by built-in extractor in WinXP and Server2003, WinZip 8, Java, and other older code,
            // you need to do one of the following: Specify UseZip64.Off, or set the Size.
            // If the file may be bigger than 4GB, or you do not need WinXP built-in compatibility, you do not need either,
            // but the zip will be in Zip64 format which not all utilities can understand.
            //   zipStream.UseZip64 = UseZip64.Off;
            newEntry.Size = fi.Length;

            zipStream.PutNextEntry(newEntry);

            // Zip the file in buffered chunks
            // the "using" will close the stream even if an exception occurs
            byte[] buffer = new byte[4096];
            using (FileStream streamReader = File.OpenRead(filename))
            {
                StreamUtils.Copy(streamReader, zipStream, buffer);
            }
            zipStream.CloseEntry();
        }
        string[] folders = Directory.GetDirectories(path);
        foreach (string folder in folders)
        {
            _compressFolder(folder, zipStream, folderOffset, excludes);
        }
    }

    #endregion

    #region Methods

    public static void CreateZipFromFolder(string folderToZipPath, string zipFullFilePath, List<string> excludes = null)
    {
        FileStream fsOut = File.Create(zipFullFilePath);
        ZipOutputStream zipStream = new ZipOutputStream(fsOut);

        zipStream.SetLevel(9); //0-9, 9 being the highest level of compression

        //zipStream.Password = password;  // optional. Null is the same as not setting. Required if using AES.

        // This setting will strip the leading part of the folder path in the entries, to
        // make the entries relative to the starting folder.
        // To include the full path for each entry up to the drive root, assign folderOffset = 0.
        int folderOffset = folderToZipPath.Length + (folderToZipPath.EndsWith("\\") ? 0 : 1);

        _compressFolder(folderToZipPath, zipStream, folderOffset, excludes);

        zipStream.IsStreamOwner = true// Makes the Close also Close the underlying stream
        zipStream.Close();
    }

    public static void ExtractZipFile(string zipFile, string destinationFolder, List<string> excludes = nullstring password = null)
    {
        ZipFile zf = null;
        try
        {
            FileStream fs = File.OpenRead(zipFile);
            zf = new ZipFile(fs);
            if (!String.IsNullOrEmpty(password))
            {
                zf.Password = password;     // AES encrypted entries are handled automatically
            }
            foreach (ZipEntry zipEntry in zf)
            {
                // Ignore directories
                if (!zipEntry.IsFile)
                    continue;

                if (excludes != null && zipEntry.IsFile)
                {
                    if (_ignore(excludes, zipEntry.Name)) continue;
                }

                String entryFileName = zipEntry.Name;
                // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
                // Optionally match entry names against a selection list here to skip as desired.
                // The unpacked length is available in the zipEntry.Size property.

                byte[] buffer = new byte[4096];     // 4K is optimum
                Stream zipStream = zf.GetInputStream(zipEntry);

                // Manipulate the output filename here as desired.
                String fullZipToPath = Path.Combine(destinationFolder, entryFileName);
                string directoryName = Path.GetDirectoryName(fullZipToPath);
                if (directoryName.Length > 0)
                    Directory.CreateDirectory(directoryName);

                // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                // of the file, but does not waste memory.
                // The "using" will close the stream even if an exception occurs.

                using (FileStream streamWriter = File.Create(fullZipToPath))
                {
                    StreamUtils.Copy(zipStream, streamWriter, buffer);
                }
            }
        }
        finally
        {
            if (zf != null)
            {
                zf.IsStreamOwner = true// Makes close also shut the underlying stream
                zf.Close(); // Ensure we release resources
            }
        }
    }

    #endregion
}

Sunday, February 4, 2018

Adding files and folders to a click once installation

Having trouble in adding specific files to your click once installation ? Morover, you want them to be placed under a specific folder ?

Here are the steps I followed that finally did it:

  1. You need to create the folder/file structure just like you want it to exist in your installation - in your visual studio project. For example, I needed two folders - x86 and x64, and the same  SQLite.Interop.dll under both
  2. Right click in your project, go to the Publish tab, then click in Application Files. Scroll down (they should be showing as the last items) to your added files, and make sure you change the Publish Status from Include (Auto) to Include. 
Should work now.



      

Thursday, February 1, 2018

Did you change your SVN ip and your Jenkins jobs are now failing? svn: E200015: No credential to try

Did you change your SVN ip and your Jenkins jobs are all failing now, even after your updated any ip references in the job configuration (stored at config.xml) to the new one ?

You may be missing this. This is was the missing bit that solved the problem for me.

In a short:

  1. Make sure you indeed changed all the old ip references in the config.xml to the new one (something I did before finding the article above, meaning this alone will not do it)
  2. Make sure you also update the ip in all credentials referencing the old ip.
  3. Restart jenkins
Your job should successfully complete now.

Saturday, January 20, 2018

Exe icon is missing in custom Build Configurations after Visual Studio build

If you add custom build configurations to your solution, make sure you manually add, for all of them, the ApplicationIcon element with the proper .ico file in the .csproj file of the main project.

  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Development|x86'">
    <ApplicationIcon>MyIcon.ico</ApplicationIcon>
  </PropertyGroup>

Wednesday, January 10, 2018

C# DateTimePicker ValueChanged event being triggered more than once, without any Value explicit assignments taking place

I spent at least an hour in investigating this issue, even adding a timer object to my form to debug.writeline the value of my datepicker objects periodically so I could have a sense of when the problem occurs.

As I noted [here], in the end my problem was with setting the MaxDate property of both parameters, to the same DateTime object. Noting this down here in case it may be of public help...

Thursday, December 21, 2017

Microsoft web architectures of the day: Web Forms vs MVC vs Web API

I was tasked today with finding out what is the best pick to convert our desktop application into a fully web based one.

Came across the 2 following links, which I found very good, where I think most of the essential topics are covered.




Wednesday, December 6, 2017

Having problems setting 2 panels in a windows form, where one is top-docked and the other fill-docked, but the fill-docked one is overflowing into the top one ?

Play with the panels "send to back" / "bring to front" (mouse right click).