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

C# 在C中打开大量文件流的替代方法#,c#,performance,unity5,filestream,disk,C#,Performance,Unity5,Filestream,Disk,在Unity中,我正在制作一个项目,该项目按程序构建一个(特别复杂的)世界,并将生成的所有数据存储在磁盘文件中以备将来使用。我已经将每个世界块的文件大小降低到8KB,并且可能能够使其更小;但是,快速连续打开和关闭这么多文件流需要额外的成本 在启动时,我创建了2970个块。我已经把FX-8300 cpu的加载时间缩短到大约20秒,硬盘速度相当快。在这里,把文件缩小不大可能对我有帮助;我似乎在打开和关闭文件流时遇到了固定成本(乘以近3000!) 所以,我在寻找另一种选择。我最近的大部分编程经验都是J

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

在启动时,我创建了2970个块。我已经把FX-8300 cpu的加载时间缩短到大约20秒,硬盘速度相当快。在这里,把文件缩小不大可能对我有帮助;我似乎在打开和关闭文件流时遇到了固定成本(乘以近3000!)

所以,我在寻找另一种选择。我最近的大部分编程经验都是Java、Python、JavaScript和D语言;所以我可能在房间里少了一头大象。它肯定是本地的。是否有可能加速文件流,将它们放入某种对象池中?或者我可以使用某种SQLite系统吗?还有更好的吗

Unity目前似乎限制了我使用.NET2.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;
}
public bool记录(块数据){
string name=BuildChunkFileName(data.Origin);
试一试{
FileStream-stream=newfilestream(BuildChunkFilePath(data.Origin)、FileMode.OpenOrCreate);
ushort[]arrayData=新的ushort[Chunk.blockSize*Chunk.blockSize*Chunk.blockSize];
int指数=0;
foreach(data.Properties中的BlockProperties道具){
arrayData[index]=props.isOpaque?(ushort)1:(ushort)0;
索引++;
}
byte[]byteData=新字节[(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);
而(!result.IsCompleted){
睡眠(100);
}
stream.Close();
}捕获(例外e){
Debug.LogException(e);
返回false;
}
返回true;
}
公共布尔读取(块数据){
int x=0,y=0,z=0;
int i=0;
string name=BuildChunkFileName(data.Origin);
字符串路径=BuildChunkFilePath(data.Origin);
试一试{
FileStream stream=新FileStream(路径,FileMode.Open);
byte[]byteData=新字节[(Chunk.blockSize*Chunk.blockSize*Chunk.blockSize)*sizeof(ushort)];
IAsyncResult result=stream.BeginRead(byteData,0,byteData.Length,null,null);
而(!result.IsCompleted){
睡眠(100);
}
ushort[]arrayData=新的ushort[Chunk.blockSize*Chunk.blockSize*Chunk.blockSize];
块复制(byteData,0,arrayData,0,byteData.Length);
对于(i=0;i
读取二进制文件的最快方法是使用所述的
file.ReadAllBytes
一次读取整个文件。该方法也有它的写对应物

使用
Thread.Sleep(100)
等待结果的效率极低。我不熟悉Unity,但请检查您是否能够使用异步等待C#语法(以及
任务
对象)进行异步 行动


此外,如果您有大量文件,研究一些面向文档的数据库可能会很有好处,这些数据库将为您优化读写部分,您只需要处理与数据库的通信。例如,MongoDB有用于二进制数据块的GridFS,但可能有一些文档数据库更适合您的用例


考虑到您没有任何关系,使用SQL数据库解决您的问题是没有意义的。但是,使用类似SQLite的东西可能仍然比使用多个文件要好。

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

使用
Thread.Sleep(100)
等待结果的效率极低。我不熟悉Unity,但请检查您是否能够使用异步等待C#语法(以及
任务
对象)进行异步 行动


此外,如果您有大量文件,研究一些面向文档的数据库可能会很有好处,这些数据库将为您优化读写部分,您只需要处理与数据库的通信。例如,MongoDB有用于二进制数据块的GridFS,但可能有一些文档数据库更适合您的用例


考虑到您没有任何关系,使用SQL数据库解决您的问题是没有意义的。但是,使用类似SQLite的东西可能仍然比使用多个文件要好。

如果您需要快速访问文件,请尝试使用内存映射文件。如果您需要可查询的关系数据访问,数据库可能是最好的方式,这一切都取决于应如何和为什么