我正在尝试创建一个工具,将文件从xbox格式转换为引擎的pc版本中可用的格式,但为了做到这一点,我必须使文件中的十六进制小端并保留字符串。
我试图调试代码,我相信瓶颈可能在'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;
}
}
我希望处理较大的文件只比小文件花费的时间少一些但是它似乎需要花费几个小时甚至根本没有处理,因为没有一个较大的文件被处理过,这与较小的文件不同。
是的,附加到字符串是一个主要的瓶颈。字符串是不可变的,就像struct
所以每次你追加它时,你实际上是在重新创建一个全新的对象。
你想要使用的是StringBuilder
对象。 StringBuilder
用于将字符串附加在一起。完成后,您可以简单地调用var mystring = stringBuilderObject.ToString();
你可以看到完整的StringBuilder
文档here
这是非常简单的代码。不确定我的字节交换是否正确,但很容易改变。
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();
}