An object with the same key already exist (DiscUtils)

  • (2 Pages)
  • +
  • 1
  • 2

18 Replies - 814 Views - Last Post: 24 July 2013 - 12:07 AM Rate Topic: -----

#1 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

An object with the same key already exist (DiscUtils)

Posted 20 July 2013 - 11:39 AM

Hello,
This is my first post so iam asking some understanding,

Iam trying to build an iso file from a directory with discutils. This code works fine with a couple of files but after a while i throws an exception stating that "An object with the same key already exists" at "isoBuilder.AddFile(fileOnIso,br.BaseStream);". I don't understand why this happens can someone please shed some light?

Quote

DiscUtils.Iso9660.CDBuilder.AddFile(String name, Stream source) -> CDBuilder.cs: line 256


public void AddtoISO(string directory,string isoFile)
    {
        BinaryReader br;
        long bytesRemain = 0;
        long totalBytesWritten = 0;
        DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
        DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);

        try
        {
            foreach (FileInfo file in currentDirToAdd.GetFiles())
            {

                string fileFullPath = file.FullName;
                string fileOnIso = fileFullPath.Substring(fileFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);

                Console.WriteLine(fileOnIso);

                br = new BinaryReader(file.OpenRead());

                while(totalBytesWritten < file.Length)
                {                       
                    bytesRemain = file.Length - totalBytesWritten;

                    br.ReadBytes(blockSize);
                    isoBuilder.AddFile(fileOnIso,br.BaseStream);

                    if(bytesRemain<blockSize)
                    {
                        totalBytesWritten += bytesRemain;
                        totalBytesAdded += bytesRemain;
                    }
                    else
                    {
                        totalBytesWritten += blockSize;
                        totalBytesAdded += blockSize;
                    }

                }

                itemsAdded++;
                totalBytesWritten = 0;

            }
            foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
            {
                string folderFullPath = subdir.FullName;
                string folderOnIso = folderFullPath.Substring(folderFullPath.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);

                isoBuilder.AddDirectory(folderOnIso);
                itemsAdded++;

                AddtoISO(subdir.FullName,isoFile,ctoken);
            }

            isoBuilder.Build(isoFile);

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }

    }




An other possible implementation avoiding streams, the drawback is that it takes too much time (over 30 mins or never completes) on a 3GB iso which when built with ultraiso for example, it takes aprox 4 mins.. any ideas?

public void AddtoISO(string directory,string isoFile)
    {

        try
        {
            DirectoryInfo rootDirToAdd = new DirectoryInfo(sourceName);
            DirectoryInfo currentDirToAdd = new DirectoryInfo(directory);

            foreach (FileInfo file in currentDirToAdd.GetFiles())
            {
                string fileOnHdd = file.FullName;
                string fileOnIso = fileOnHdd.Substring(fileOnHdd.IndexOf(rootDirToAdd.Name) + rootDirToAdd.Name.Length + 1);
                Console.WriteLine(fileOnIso);
                isoBuilder.AddFile(fileOnIso,fileOnHdd);
                itemsAdded++;
            }
            foreach (DirectoryInfo subdir in currentDirToAdd.GetDirectories())
            {
                itemsAdded++;
                AddtoISO(subdir.FullName,isoFile,ctoken);
            }

            isoBuilder.Build(isoFile);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            Console.WriteLine(ex.StackTrace);
        }

    }


The exception is thrown when ever the directory structure is the following:

\boot\boot.ext

It seems like it creates the key for boot directory and when it encounters boot.ext file it falsely thinks that it is a double addition. In other words when the files contains the name of its containing directory.

Test building dsl-4.11.rc1.iso

Quote

index.html
boot
boot\isolinux
boot\isolinux\boot.cat
boot\isolinux\boot.msg
boot\isolinux\f2
boot\isolinux\f3
boot\isolinux\german.kbd
boot\isolinux\isolinux.bin
boot\isolinux\isolinux.cfg
boot\isolinux\linux24
boot\isolinux\logo.16
boot\isolinux\minirt24.gz
KNOPPIX
KNOPPIX\KNOPPIX
Problem on KNOPPIX\KNOPPIX


Is This A Good Question/Topic? 0
  • +

Replies To: An object with the same key already exist (DiscUtils)

#2 Momerath  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 1012
  • View blog
  • Posts: 2,444
  • Joined: 04-October 09

Re: An object with the same key already exist (DiscUtils)

Posted 20 July 2013 - 02:20 PM

Without seeing whatever class isobuilder is, there is nothing we can do. But I can make a guess. It looks like you are stripping off the path information which uniquely identifies a file. When you get two of the same name, the error happens.
Was This Post Helpful? 0
  • +
  • -

#3 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 12:39 AM

Hi, Thanks for replying. isobuilder is just an instanse of CDBuilder class provided by DiscUtils library responsible for building the iso file.
Now the stripping must occur because of the arguments Addfile() method demands. On the first implementation posted The first is the path of the file inside the iso hierarchy and the second is the stream to the full path of the "real" file on the HDD.

Now let's assume that C:\Test is the root dir and tha it must be excluded from the final iso.

e.g: C:\Test\boot\boot.bin <- here i need the whole path to open the stream which is ok. next i need to strip off " C:\Test" so the file boot.bin is correctly added in the iso as "\boot\boot.bin".

I cant see the wrong part in the stripping care to demonstrate?

Thank you very much
Was This Post Helpful? 0
  • +
  • -

#4 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 02:41 AM

I forgot to mention that on my second implementation. it works like a charm except for big isos like 3GB and more which just takes forever without completing but never throwing any exceptions so my paths should be ok (?)
Was This Post Helpful? 0
  • +
  • -

#5 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 07:29 AM

At last some progress.. the error is not in any of the given paths but im my assumption that i had to keep calling isobuilder.Addfile() until the filestream has been added to the iso entirely.
I just had to move:

isoBuilder.AddFile(fileOnIso,br.BaseStream);

Before the foreach closing bracket. This way it will no have to be added again and again in the iso.
One final problen is at the line

isoBuilder.Build(isoFile);


Where it complains about the file being closed. I tried to correct it with:

FileInfo fi = new FileInfo(isoFile);
isoBuilder.Build(fi.OpenWrite());

But it didnt help. Please someone give me the final push to solve it.
Was This Post Helpful? 0
  • +
  • -

#6 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 10:12 AM

Last attempt

File.Create(isoFile);
File.SetAttributes(isoFile, FileAttributes.Normal);
FileInfo fi = new FileInfo(isoFile);
isoBuilder.Build(fi.OpenWrite());


Quote

The process cannot access the file because it is being used by another process


What am i missing?
Was This Post Helpful? 0
  • +
  • -

#7 andrewsw  Icon User is offline

  • Fire giant boob nipple gun!
  • member icon

Reputation: 3524
  • View blog
  • Posts: 12,031
  • Joined: 12-December 12

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 10:49 AM

Which line does the error occur on?

This post has been edited by andrewsw: 21 July 2013 - 10:57 AM

Was This Post Helpful? 0
  • +
  • -

#8 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 11:12 AM

Oops i skipped that sorry.
isoBuilder.Build(fi.OpenWrite());


Quote

\bin\Debug\myIso.iso - The process cannot access the file because it is being used by another process

Was This Post Helpful? 0
  • +
  • -

#9 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3590
  • View blog
  • Posts: 11,166
  • Joined: 05-May 12

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 12:20 PM

Based on the documentation here: http://discutils.codeplex.com/ , all you needed was to pass in the filename of the target .ISO file. Why do you need to open the stream for writing yourself?
Was This Post Helpful? 0
  • +
  • -

#10 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 12:42 PM

because that way i get "cannot access a closed file" on the same line of code.. i can't figure out whats wrong..
Was This Post Helpful? 0
  • +
  • -

#11 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3590
  • View blog
  • Posts: 11,166
  • Joined: 05-May 12

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 12:46 PM

Since DiscUtils is open source, you could trace into the Build() call to see what is happening.
Was This Post Helpful? 0
  • +
  • -

#12 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 21 July 2013 - 02:16 PM

public void Build(Stream output)
        {
            using (Stream src = Build())
            {
                byte[] buffer = new byte[64 * 1024];
                int numRead = src.Read(buffer, 0, buffer.Length);
                while (numRead != 0)
                {
                    output.Write(buffer, 0, numRead);
                    numRead = src.Read(buffer, 0, buffer.Length);
                }
            }
        }

        /// <summary>
        /// Writes the stream contents to a file.
        /// </summary>
        /// <param name="outputFile">The file to write to.</param>
        public void Build(string outputFile)
        {
            using (FileStream destStream = new FileStream(outputFile, FileMode.Create, FileAccess.Write))
            {
                Build(destStream);
            }
        }


I cant see anything "bad" just one function calls the other. any suggestions?
Was This Post Helpful? 0
  • +
  • -

#13 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 22 July 2013 - 02:24 AM

Iam really at a loss here..
With my first implementation, Build() fails with the errors mentioned above.

With my second implementation, if the iso is a small one the iso is succesfully built. if i supply a e.g a 3GB directory the proccess slows down after adding a bunch of files and never completes. I' ve let it run for an hour and then i got bored and stopped it.

Iam clueless, i don't know what to do from here. Maybe someone could test my code on his machine??

Thank you all.
Was This Post Helpful? 0
  • +
  • -

#14 Skydiver  Icon User is offline

  • Code herder
  • member icon

Reputation: 3590
  • View blog
  • Posts: 11,166
  • Joined: 05-May 12

Re: An object with the same key already exist (DiscUtils)

Posted 22 July 2013 - 05:35 AM

For your first implementation, actually trace into the code with the debugger instead of just inspecting the source code.

For your second implementation, instead of getting bored and just stopping it, break into the the code with the debugger and see where it is hanging. (Or if DiscUtils has verbose logging or tracing, try turning that on to see where it is getting stuck.)
Was This Post Helpful? 0
  • +
  • -

#15 Sparky414  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 13
  • Joined: 20-July 13

Re: An object with the same key already exist (DiscUtils)

Posted 22 July 2013 - 06:18 AM

Hey thanks,

The point for the second one is that it does not hang!? it just slows down. say it takes a sec to add a file and print the next one on the screen ok? after a while i see it proccesses the same file for 10mins! and moves to the next one at even slower speed! So i can not trace something that just slows down.. I dont know if you can understand me..

This is why i decided to let it run for so long. it doesn't hang it just slows down veeery veery much and it just proccessed a 75Kb file!


For the first one: I traced into:

Quote

DiscUtils.Iso9660.FileExtent.Read(Int64 diskOffset, Byte[] block, Int32 of
fset, Int32 count)at c:\root\codeplex\discutils\src\Iso9660\FileExtent.cs:53


internal override int Read(long diskOffset, byte[] block, int offset, int count)
        {
            long relPos = diskOffset - Start;
            int totalRead = 0;

            // Don't arbitrarily set position, just in case stream implementation is
            // non-seeking, and we're doing sequential reads
           [u] if (_readStream.Position != relPos)[/u]
            {
                _readStream.Position = relPos;
            }

            // Read up to EOF
            int numRead = _readStream.Read(block, offset, count);
            totalRead += numRead;
            while (numRead > 0 && totalRead < count)
            {
                numRead = _readStream.Read(block, offset + totalRead, count - totalRead);
                totalRead += numRead;
            }

            return totalRead;
        }


And the underlined code has the problem but i cant figure what it is.. I'll keep trying. The weird thing is that this code for my second method works!

Thanks again i hope im not tiring you very much
Was This Post Helpful? 0
  • +
  • -

  • (2 Pages)
  • +
  • 1
  • 2