ArgumentException "an item with this key has already been added" when accessing a zip file

Aug 17, 2010 at 2:01 AM
So I've been working on a simple project: make a GUI that takes selected directories, gets files in them, and creates a "backup" zip file in a specified directory. I started using DotNetZip was was incredibly pleased with how simple it made the process and how well it compressed things. However, recently I started running to program, and I would only be able to run through a backup process once, maybe twice, and then this exception would be thrown any time I tried to read the zip file: System.ArgumentException was unhandled Message="An item with the same key has already been added." Source="mscorlib" StackTrace: at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value) at Ionic.Zip.ZipFile.ReadCentralDirectory(ZipFile zf) at Ionic.Zip.ZipFile.ReadIntoInstance(ZipFile zf) at Ionic.Zip.ZipFile.Read(String fileName, TextWriter statusMessageWriter, Encoding encoding, EventHandler`1 readProgress) at Ionic.Zip.ZipFile.Read(String fileName, TextWriter statusMessageWriter, Encoding encoding) at Ionic.Zip.ZipFile.Read(String fileName) at FileSafe.Form1.BackUp() in C:\Users\Cid the Coatrack\Documents\Visual Studio 2005\Projects\FileSafe\FileSafe\Form1.cs:line 317 at FileSafe.Form1.BackUpButton_Click(Object sender, EventArgs e) in C:\Users\Cid the Coatrack\Documents\Visual Studio 2005\Projects\FileSafe\FileSafe\Form1.cs:line 522 at System.Windows.Forms.Control.OnClick(EventArgs e) at System.Windows.Forms.Button.OnClick(EventArgs e) at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent) at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ButtonBase.WndProc(Message& m) at System.Windows.Forms.Button.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at FileSafe.Program.Main() in C:\Users\Cid the Coatrack\Documents\Visual Studio 2005\Projects\FileSafe\FileSafe\Program.cs:line 17 at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() Again, after maybe one successful backup, this exception is thrown any time I attempt to read the zip file. I'm just doing a simple using statement to read the file: using(ZipFile zip = ZipFile.Read(BackUpDirectory + "UserBackup.zip") { //my backup code, which is rather length - if you'd like to see it, or portions, just ask } After extensive search of the internet, I found that this particular error is most found when there's a duplicate entry somewhere - which does make sense. However, I'm not sure where or how I'm making such a "duplicate entry" to throw this exception. I thought perhaps it wasn't disposing properly despite the using statement, and was tripping when it found the old "undisposed" file, but even after explicitly disposing of the zip, the error still popped up. This is the one and only problem preventing this so far very successful project from completion. Any suggestions?
Aug 17, 2010 at 2:03 AM
Oh my, the formatting on that post didn't go through correctly at all. My apologies for that block of babble. It also won't let me get in there to fix it... :'(
Coordinator
Aug 20, 2010 at 12:54 PM

Can you make another post then, with better formatting?  

 

Aug 20, 2010 at 11:09 PM

Let's try this one:

So I've been working on a simple project: make a GUI that takes selected directories, gets files in them, and creates a "backup" zip file in a specified directory. I started using DotNetZip was was incredibly pleased with how simple it made the process and how well it compressed things. However, recently I started running to program, and I would only be able to run through a backup process once, maybe twice, and then this exception would be thrown any time I tried to read the zip file:

------------------

System.ArgumentException was unhandled

Message="An item with the same key has already been added."

Source="mscorlib"

StackTrace: at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)

at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)

at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)

at Ionic.Zip.ZipFile.ReadCentralDirectory(ZipFile zf)

at Ionic.Zip.ZipFile.ReadIntoInstance(ZipFile zf)

at Ionic.Zip.ZipFile.Read(String fileName, TextWriter statusMessageWriter, Encoding encoding, EventHandler`1 readProgress)

at Ionic.Zip.ZipFile.Read(String fileName, TextWriter statusMessageWriter, Encoding encoding)

at Ionic.Zip.ZipFile.Read(String fileName) at FileSafe.Form1.BackUp() in C:\Users\Cid the Coatrack\Documents\Visual Studio 2005\Projects\FileSafe\FileSafe\Form1.cs:line 317

at FileSafe.Form1.BackUpButton_Click(Object sender, EventArgs e) in C:\Users\Cid the Coatrack\Documents\Visual Studio 2005\Projects\FileSafe\FileSafe\Form1.cs:line 522

at System.Windows.Forms.Control.OnClick(EventArgs e)

at System.Windows.Forms.Button.OnClick(EventArgs e)

at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)

at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)

at System.Windows.Forms.Control.WndProc(Message& m)

at System.Windows.Forms.ButtonBase.WndProc(Message& m)

at System.Windows.Forms.Button.WndProc(Message& m)

at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)

at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)

at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)

at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)

at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)

at System.Windows.Forms.Application.Run(Form mainForm)

at FileSafe.Program.Main() in C:\Users\Cid the Coatrack\Documents\Visual Studio 2005\Projects\FileSafe\FileSafe\Program.cs:line 17

at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)

at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)

at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state)

at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)

at System.Threading.ThreadHelper.ThreadStart()

---------------------

Again, after maybe one successful backup, this exception is thrown any time I attempt to read the zip file. I'm just doing a simple using statement to read the file:

---------------------

using(ZipFile zip = ZipFile.Read(BackUpDirectory + "UserBackup.zip")

{

     //my backup code, which is rather lengthy - if you'd like to see it, or portions, just ask

}

---------------------

After extensive search of the internet, I found that this particular error is most found when there's a duplicate entry somewhere - which does make sense. However, I'm not sure where or how I'm making such a "duplicate entry" to throw this exception. I thought perhaps it wasn't disposing properly despite the using statement, and was tripping when it found the old "undisposed" file, but even after explicitly disposing of the zip, the error still popped up. This is the one and only problem preventing this so far very successful project from completion. Any suggestions?

Aug 25, 2010 at 8:40 AM

I ran into the exact same problem and as you say, the culprit is indeed a duplicate entry... or almost duplicate. Since non-windows systems can have case sensitive filenames (you can have readme.txt and README.TXT in the same directory) it becomes an obstacle for DotNetZip. DotNetZip indexes the archive into a Dictionary and Dictionary's keys are case insensitive - so it considers readme and README the same file, which is why it throws the exception.

 

In order to solve this you'd need to poke the DotNetZip internals a bit and switch the Dictionary to another container, one that is case sensitive.

Aug 25, 2010 at 7:13 PM
Jusas wrote:

In order to solve this you'd need to poke the DotNetZip internals a bit and switch the Dictionary to another container, one that is case sensitive.

That makes perfect sense, and it fits with some of the other things I've seen online when researching this problem.  Now my question is, how might one go about poking DotNetZip's internals?

Aug 26, 2010 at 10:20 AM

Well you can download the source package and locate the file where read operation (ReadCentralDirectory(ZipFile zf)) is done, that's a good starting point. Basically everything that uses the Dictionary must be changed to use some other container. I have no idea how much work that would involve though. It is however something that should be patched since it can be considered a bug, obviously it should be able to read the zip contents but because a Dictionary was used to form the index it just doesn't work.

Aug 27, 2010 at 1:58 AM

It seems using a NameValueCollection instead of just a Dictionary might solve the problem, at least from the description I found.  I'll try that and tell you if that works - and then maybe DotNetZip can consider that for a patch or something.

Aug 27, 2010 at 2:27 AM

Could just be that my coding skills aren't up to snuff, but I can't get it to accept changing to NameValeCollection.  The dictionary that throws the exception is called _entries, and oddly enough, there is another version of _entries in the source code, one done as a List<ZipEntry> instead of a Dictionary.  That is commented out and the dictionary form is used instead.  I wonder why that switch occurred, and why they didn't just eliminate the older code...

Aug 27, 2010 at 1:41 PM

The ctor for a Dictionary accepts an IEqualityComparer. Therefore you can specify 'StringComparer.OrdinalIgnoreCase' for the comparer and have a case-insensitive lookup on the dictionary key.

Sep 18, 2010 at 6:56 PM

Ah, as it turns out, the error lay not with DotNetZip, but with Windows.  Somehow, Windows allowed two files to have the exact same name and extension in the same folder.  They both worked fine, but they were literally completely identical.  So, when DotNetZip when to zip them, there were two files of the same name.  When it went to read them, it saw that they had the same file, that something of that key had already been added to the dictionary, and threw the error.  I deleted the random duplicate file (still don't know how it got there in the first place), and everything worked fine.  Simple solutions are usually there; the bugger is in finding them.