在运行时将地形数据保存到文件的最佳方法是什么?
What's the best way to save terraindata to file in Runtime?
我的游戏允许用户在运行时修改地形,但现在我需要保存所述地形。我试过直接将地形的高度图保存到文件中,但是写这个 513x513 高度图需要将近两分钟的时间。
解决这个问题的好方法是什么?有什么方法可以优化写入速度,还是我的方法不对?
public static void Save(string pathraw, TerrainData terrain)
{
//Get full directory to save to
System.IO.FileInfo path = new System.IO.FileInfo(Application.persistentDataPath + "/" + pathraw);
path.Directory.Create();
System.IO.File.Delete(path.FullName);
Debug.Log(path);
//Get the width and height of the heightmap, and the heights of the terrain
int w = terrain.heightmapWidth;
int h = terrain.heightmapHeight;
float[,] tData = terrain.GetHeights(0, 0, w, h);
//Write the heights of the terrain to a file
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
//Mathf.Round is to round up the floats to decrease file size, where something like 5.2362534 becomes 5.24
System.IO.File.AppendAllText(path.FullName, (Mathf.Round(tData[x, y] * 100) / 100) + ";");
}
}
}
作为旁注,Mathf.Round 似乎不会对节省时间产生太大影响,如果有的话。
您正在进行许多小的单个文件 IO 调用。文件 IO 总是耗时且昂贵的,因为它包含打开文件、写入文件、保存文件和关闭文件。
相反,我宁愿使用例如生成完整的字符串StringBuilder
这也比使用
这样的东西更有效
var someString
为了(...)
{
一些字符串 += "xyz"
}
因为后者总是分配一个新的string
.
然后使用例如a FileStream and StringWriter.WriteAsync(string)
用于编写异步。
也宁愿使用 Path.Combine
而不是通过 /
直接连接字符串。 Path.Combine
根据 OS 所使用的连接器自动使用正确的连接器。
而不是 FileInfo.Directory.Create
而是使用 Directory.CreateDirectory
如果目录已经存在则不会抛出异常。
类似
using System.IO;
...
public static void Save(string pathraw, TerrainData terrain)
{
//Get full directory to save to
var filePath = Path.Combine(Application.persistentDataPath, pathraw);
var path = new FileInfo(filePath);
Directory.CreateDirectory(path.DirectoryName);
// makes no sense to delete
// ... rather simply overwrite the file if exists
//File.Delete(path.FullName);
Debug.Log(path);
//Get the width and height of the heightmap, and the heights of the terrain
var w = terrain.heightmapWidth;
var h = terrain.heightmapHeight;
var tData = terrain.GetHeights(0, 0, w, h);
// put the string together
// StringBuilder is more efficient then using
// someString += "xyz" because latter always allocates a new string
var stringBuilder = new StringBuilder();
for (var y = 0; y < h; y++)
{
for (var x = 0; x < w; x++)
{
// also add the linebreak if needed
stringBuilder.Append(Mathf.Round(tData[x, y] * 100) / 100).Append(';').Append('\n');
}
}
using (var file = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
{
using (var streamWriter = new StreamWriter(file, Encoding.UTF8))
{
streamWriter.WriteAsync(stringBuilder.ToString());
}
}
}
您可能想要指定 如何 准确地指定数字应以一定的精度打印,例如
(Mathf.Round(tData[x, y] * 100) / 100).ToString("0.00000000");
我的游戏允许用户在运行时修改地形,但现在我需要保存所述地形。我试过直接将地形的高度图保存到文件中,但是写这个 513x513 高度图需要将近两分钟的时间。
解决这个问题的好方法是什么?有什么方法可以优化写入速度,还是我的方法不对?
public static void Save(string pathraw, TerrainData terrain)
{
//Get full directory to save to
System.IO.FileInfo path = new System.IO.FileInfo(Application.persistentDataPath + "/" + pathraw);
path.Directory.Create();
System.IO.File.Delete(path.FullName);
Debug.Log(path);
//Get the width and height of the heightmap, and the heights of the terrain
int w = terrain.heightmapWidth;
int h = terrain.heightmapHeight;
float[,] tData = terrain.GetHeights(0, 0, w, h);
//Write the heights of the terrain to a file
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
//Mathf.Round is to round up the floats to decrease file size, where something like 5.2362534 becomes 5.24
System.IO.File.AppendAllText(path.FullName, (Mathf.Round(tData[x, y] * 100) / 100) + ";");
}
}
}
作为旁注,Mathf.Round 似乎不会对节省时间产生太大影响,如果有的话。
您正在进行许多小的单个文件 IO 调用。文件 IO 总是耗时且昂贵的,因为它包含打开文件、写入文件、保存文件和关闭文件。
相反,我宁愿使用例如生成完整的字符串StringBuilder
这也比使用
var someString 为了(...) { 一些字符串 += "xyz" }
因为后者总是分配一个新的string
.
然后使用例如a FileStream and StringWriter.WriteAsync(string)
用于编写异步。
也宁愿使用 Path.Combine
而不是通过 /
直接连接字符串。 Path.Combine
根据 OS 所使用的连接器自动使用正确的连接器。
而不是 FileInfo.Directory.Create
而是使用 Directory.CreateDirectory
如果目录已经存在则不会抛出异常。
类似
using System.IO;
...
public static void Save(string pathraw, TerrainData terrain)
{
//Get full directory to save to
var filePath = Path.Combine(Application.persistentDataPath, pathraw);
var path = new FileInfo(filePath);
Directory.CreateDirectory(path.DirectoryName);
// makes no sense to delete
// ... rather simply overwrite the file if exists
//File.Delete(path.FullName);
Debug.Log(path);
//Get the width and height of the heightmap, and the heights of the terrain
var w = terrain.heightmapWidth;
var h = terrain.heightmapHeight;
var tData = terrain.GetHeights(0, 0, w, h);
// put the string together
// StringBuilder is more efficient then using
// someString += "xyz" because latter always allocates a new string
var stringBuilder = new StringBuilder();
for (var y = 0; y < h; y++)
{
for (var x = 0; x < w; x++)
{
// also add the linebreak if needed
stringBuilder.Append(Mathf.Round(tData[x, y] * 100) / 100).Append(';').Append('\n');
}
}
using (var file = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
{
using (var streamWriter = new StreamWriter(file, Encoding.UTF8))
{
streamWriter.WriteAsync(stringBuilder.ToString());
}
}
}
您可能想要指定 如何 准确地指定数字应以一定的精度打印,例如
(Mathf.Round(tData[x, y] * 100) / 100).ToString("0.00000000");