While using .NET System.IO.Compression.ZipFile.CreateFromDirectory class the outcome zip is badly extracted on system with forward-slash directory separator.
The correct work around for this issue is as follows
class MyEncoder : UTF8Encoding
{
public MyEncoder() : base(true)
{
}
public override byte[] GetBytes(string s)
{
s = s.Replace("\\", "/");
return base.GetBytes(s);
}
}
NOTE: This is slightly different from a previous answer.
The key difference is in the : base(true)
This is important or the .NET ZipArchive class will NOT recognize the encoder as a UTF-8 encoder and will NOT mark the correct general purpose bit, and thus extracting the resulting zip file with any other zip program will assume the zip entry name is in a non-unicode encoding which might result in a mangled filename.
The reason is due to a internal call in .NET to check if the custom encoder is .equals(Encoding.UTF8)
which isn't true unless true
is passed for the encoderShouldEmitUTF8Identifier like Encoding.UTF8
Microsoft has addressed this in .NET 4.6.1:
Starting with apps that target the .NET Framework 4.6.1, the path separator used in the ZipArchiveEntry.FullName property has changed from the backslash ("\") used in previous versions of the .NET Framework to a forward slash ("/"). System.IO.Compression.ZipArchiveEntry objects are created by calling one of the overloads of the ZipFile.CreateFromDirectory method.
Note:
In addition, apps that target previous versions of the .NET Framework but are running on the .NET Framework 4.6.1 and later versions can opt in to this behavior by adding a configuration setting to the section of the application configuration file.
To overcome this problem a workaround exists:
class MyEncoder : UTF8Encoding
{
public MyEncoder()
{
}
public override byte[] GetBytes(string s)
{
s = s.Replace("\\", "/");
return base.GetBytes(s);
}
}
System.IO.Compression.ZipFile.CreateFromDirectory("C:/ABC", "C:/tmp/ABC.zip", CompressionLevel.Fastest, false, new MyEncoder());