В чем проблема производительности в этом коде преобразования файлов? - PullRequest
0 голосов
/ 18 февраля 2019

Я пытаюсь создать инструмент, который преобразует файлы из формата xbox в формат, используемый в компьютерной версии движка, однако для этого я должен сделать шестнадцатеричный код в файле с прямым порядком байтов и сохранить строки.

Я попытался отладить код и считаю, что узкое место может быть в функции 'ReadHex', особенно при добавлении к строке 'hex'.

    static void Main(string[] args)
    {
        Console.Write("Enter the directory containing files: ");
        var path = Console.ReadLine();

        string[] files = Directory.GetFiles(path);

        foreach (string file in files)
        {
            string hex = ReadHex(file);
            var x = FindHexStrings(hex);
            var removed = x.Item1;
            var positions = x.Item2;

            for (int i = 0; i < removed.Count; i++)
            {
                hex = hex.Remove(positions[i], removed[i].Length);
            }

            hex = ChunkIntoFourBytes(hex);

            for (int i = 0; i < removed.Count; i++)
            {
                hex = hex.Insert(positions[i], removed[i]);
            }

            var stream = new FileStream( Path.GetFileName(file) , FileMode.Create, FileAccess.ReadWrite);

            WriteHexStringToFile(hex, stream);

            stream.Close();
        }
        Console.ReadLine();
    }

    private static void WriteHexStringToFile(string hexString, FileStream stream)
    {
        var twoCharacterBuffer = new StringBuilder();
        var oneByte = new byte[1];
        foreach (var character in hexString.Where(c => c != ' '))
        {
            twoCharacterBuffer.Append(character);

            if (twoCharacterBuffer.Length == 2)
            {
                oneByte[0] = Convert.ToByte(twoCharacterBuffer.ToString(), 16);
                stream.Write(oneByte, 0, 1);
                twoCharacterBuffer.Clear();
            }
        }
    }

    static string LittleEndian(string num)
    {
        int number = Convert.ToInt32(num, 16);
        byte[] bytes = BitConverter.GetBytes(number);
        string retval = "";
        foreach (byte b in bytes)
            retval += b.ToString("X2");
        return retval;
    }

    public static void ConvertHexToAscii(string hexString)
    {
        string ascii = string.Empty;

        for (int i = 0; i < hexString.Length; i += 2)
        {
            string hs = string.Empty;

            hs = hexString.Substring(i, 2);
            uint decval = System.Convert.ToUInt32(hs, 16);
            char character = System.Convert.ToChar(decval);
            ascii += character;

        }

        Console.WriteLine(ascii);
    }

    static Tuple<List<string>, List<int>> FindHexStrings(string str)
    {
        int position=-1;
        string hexstring="";

        List<string> removed = new List<string>();
        List<int> positions = new List<int>();

        int chunkSize = 2;
        int stringLength = str.Length;
        for (int i = 0; i < stringLength; i += chunkSize)
        {
            if (i + chunkSize > stringLength) chunkSize = stringLength - i;
            if (int.Parse(str.Substring(i, chunkSize), System.Globalization.NumberStyles.HexNumber) >= 0x30 && int.Parse(str.Substring(i, chunkSize), System.Globalization.NumberStyles.HexNumber) <= 0x39 || int.Parse(str.Substring(i, chunkSize), System.Globalization.NumberStyles.HexNumber) >= 0x41 && int.Parse(str.Substring(i, chunkSize), System.Globalization.NumberStyles.HexNumber) <= 0x5A || int.Parse(str.Substring(i, chunkSize), System.Globalization.NumberStyles.HexNumber) >= 0x61 && int.Parse(str.Substring(i, chunkSize), System.Globalization.NumberStyles.HexNumber) <= 0x7A || int.Parse(str.Substring(i, chunkSize), System.Globalization.NumberStyles.HexNumber) == 0x5F) //Is valid hex character for ascii sequence
            {
                if (hexstring.Length == 0) { position = i; }

                hexstring += str.Substring(i, chunkSize);
            }
            else
            {
                if (hexstring.Length >= 8) { removed.Add(hexstring); positions.Add(position); }

                position = -1;
                hexstring = "";
            }
        }

        Console.WriteLine("Removed strings:");
        removed.ForEach(ConvertHexToAscii);
        Console.WriteLine("\nPositions:");
        positions.ForEach(Console.WriteLine);
        return new Tuple<List<string>, List<int>>(removed, positions);
    }

    static string ChunkIntoFourBytes(string str)
    {
        string final = "";

        int chunkSize = 8;
        int stringLength = str.Length;
        for (int i = 0; i < stringLength; i += chunkSize)
        {
            if (i + chunkSize > stringLength) chunkSize = stringLength - i;
            final+=LittleEndian(str.Substring(i, chunkSize));
        }

        return final;
    }

    static string ReadHex(string directory)
    {
        FileStream fs = new FileStream(directory, FileMode.Open);
        int hexIn;
        string hex = "";

        for (int i = 0; (hexIn = fs.ReadByte()) != -1; i++)
        {
            hex += string.Format("{0:X2}", hexIn);
        }

        return hex;
    }

}

Я ожидал обработки большего размерафайлы занимают лишь небольшое количество времени дольше, чем маленькие файлы, однако, кажется, что это занимает несколько часов или вообще не обрабатывается, поскольку ни один из больших файлов не был обработан, в отличие от меньших.

Ответы [ 2 ]

0 голосов
/ 18 февраля 2019

Вот очень простой код.Не уверен, что я правильно изменил байт, но его легко изменить.

        static void Main(string[] args)
        {
            Console.Write("Enter the directory containing files: ");
            var path = Console.ReadLine();

            string[] files = Directory.GetFiles(path);
            byte[] temp = new byte[4];
            foreach (string file in files)
            {
                byte[] buffer = File.ReadAllBytes(file);
                for (int i = 0; i < buffer.Count(); i += 4)
                {
                    temp[0] = buffer[i + 3];
                    temp[1] = buffer[i + 2];
                    temp[2] = buffer[i + 1];
                    temp[3] = buffer[i];

                    Array.Copy(temp, 0, buffer, i, 4);

                }
                File.WriteAllBytes(file, buffer);
            }
            Console.ReadLine();
        }
0 голосов
/ 18 февраля 2019

Да, добавление к строке является основным узким местом.Строка является неизменной, как struct, поэтому каждый раз, когда вы добавляете ее, вы фактически воссоздаете новый объект.

То, что вы хотите использовать, - это объект StringBuilder.StringBuilder предназначен для добавления строки вместе.Когда вы закончите, просто позвоните по номеру var mystring = stringBuilderObject.ToString();

. Вы можете просмотреть полную документацию StringBuilder здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...