3

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?

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);
        }

    }

Update An other possible implementation avoiding streams, the drawback is that it takes too much time (over 30 mins) 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);
        }

    }

Update:

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

\boot\boot

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

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

Update 2

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 problem 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.

4

1 回答 1

1

我知道这已经很老了,但我想如果将来有其他人需要这方面的帮助,我会发帖。

下面是我用来构建 ISO 的快速高效的函数DiscUtils.Iso9660

public string CreateIsoImage(string sourceDrive, string targetIso, string volumeName)
{
    try
    {
        var srcFiles = Directory.GetFiles(sourceDrive, "*", SearchOption.AllDirectories);
        var iso = new CDBuilder
        {
            UseJoliet = true,
            VolumeIdentifier = volumeName
        };

        foreach (var file in srcFiles)
        {
            var fi = new FileInfo(file);
            if (fi.Directory.Name == sourceDrive)
            {
                iso.AddFile($"{fi.Name}", fi.FullName);
                continue;
            }
            var srcDir = fi.Directory.FullName.Replace(sourceDrive, "").TrimEnd('\\');
            iso.AddDirectory(srcDir);
            iso.AddFile($"{srcDir}\\{fi.Name}", fi.FullName);
        }

        iso.Build(targetIso);
        return "Success";
    }
    catch (Exception ex)
    {
        return ex.Message;
    }
}

用法:

CreateIsoImage("D:\\", "C:\\Temp\\MyIsoImage.iso", "MyVolumeName");
于 2020-11-23T23:34:12.320 回答