替代在C#中打开大量文件流

时间:2018-02-06 01:08:20

标签: c# performance unity5 filestream disk

在Unity中,我正在制作一个程序,它在程序上构建一个(特别复杂的)世界,并将所有生成的数据存储在磁盘文件中以备将来使用。我已经将文件大小降低到每个世界块8 KB,并且可能使它更小;但是,快速连续打开和关闭这么多文件流会产生额外的成本。

启动时,我创建了2,970个块。我在FX-8300 CPU上的加载时间下降到大约20秒,并且硬盘速度相当快。使文件变小不太可能在这里帮助我;打开和关闭文件流时,我似乎遇到了固定的成本(乘以近3000!)

所以,我正在寻找另一种选择。我最近的编程经验大部分是Java,Python,JavaScript和D;所以我可能在房间里想念一头大象。 LTS肯定必须是本地的。是否有可能加速FileStreams,将它们抛在某种对象池中?或者我可以使用某种SQLite系统吗?那里有更好的东西吗?

Unity目前似乎限制我使用.NET 2.0功能,但是大量的文件管理是一项相当普遍的任务(在更广泛的意义上),我无法帮助但感觉我正在做这是一种天真的方式。

感谢所有输入!

有很多代码,但相关部分可能就是这样。如果您需要查看其他任何内容,请与我们联系。

public bool record(BlockData data) {
    string name = BuildChunkFileName(data.Origin);
    try {
        FileStream stream = new FileStream(BuildChunkFilePath(data.Origin), FileMode.OpenOrCreate);

        ushort[] arrayData = new ushort[Chunk.blockSize * Chunk.blockSize * Chunk.blockSize];

        int index = 0;
        foreach(BlockProperties props in data.Properties) {
            arrayData[index] = props.isOpaque ? (ushort)1 : (ushort)0;
            index++;
        }

        byte[] byteData = new byte[(Chunk.blockSize * Chunk.blockSize * Chunk.blockSize) * sizeof(ushort)];
        Buffer.BlockCopy(arrayData, 0, byteData, 0, (Chunk.blockSize * Chunk.blockSize * Chunk.blockSize) * sizeof(ushort));
        IAsyncResult result = stream.BeginWrite(byteData, 0, byteData.Length, null, null);

        while(!result.IsCompleted) {
            Thread.Sleep(100);
        }

        stream.Close();
    } catch(Exception e) {
        Debug.LogException (e);
        return false;
    }
    return true;
}

public bool read(BlockData data) {
    int x = 0, y = 0, z = 0;
    int i = 0;

    string name = BuildChunkFileName (data.Origin);
    string path = BuildChunkFilePath (data.Origin);

    try {
        FileStream stream = new FileStream(path, FileMode.Open);

        byte[] byteData = new byte[(Chunk.blockSize * Chunk.blockSize * Chunk.blockSize) * sizeof(ushort)];
        IAsyncResult result = stream.BeginRead(byteData, 0, byteData.Length, null, null);

        while(!result.IsCompleted) {
            Thread.Sleep(100);
        }

        ushort[] arrayData = new ushort[Chunk.blockSize * Chunk.blockSize * Chunk.blockSize];
        Buffer.BlockCopy(byteData, 0, arrayData, 0, byteData.Length);

        for(i = 0; i < arrayData.Length; i++) {
            x = i % Chunk.blockSize;
            y = (i / (Chunk.blockSize)) % Chunk.blockSize;
            z = i / (Chunk.blockSize * Chunk.blockSize);
            data.Properties [x, y, z].isOpaque = arrayData [i] == 0 ? false : true;
        }

        stream.Close();
    } catch(Exception) {
        // a lot of specific exception handling here, the important part
        // is that I return false so I know there was a problem.
        return false;
    }

    return true;
}

1 个答案:

答案 0 :(得分:3)

读取二进制文件的最快方法是使用File.ReadAllBytes一次读取整个文件,如here所述。该方法也有写对应物。

使用Thread.Sleep(100)是一种非常低效的等待结果的方法。我不熟悉Unity,但检查你是否能够使用async-await C#语法(以及Task对象)进行异步 操作

此外,如果您拥有大量文件,那么查看一些面向文档的数据库可能会有所帮助,这些数据库将为您优化读写部分,您只需要处理与数据库的通信。例如,MongoDB具有用于二进制数据块的GridFS,但可能有一些文档数据库甚至更适合您的用例。

考虑到您没有任何关系,使用SQL数据库没有任何意义。但是,使用像SQLite这样的东西可能比使用多个文件更好。