数组大小基于可用的物理内存

时间:2012-03-12 18:52:10

标签: c# arrays

我正在尝试制作加密算法。 我可以读取一个文件并将其转换为字节而没有任何问题,并将字节保存在byteArray中。

问题是我目前正在创建这样的数组大小:

byte[] FileArray =new byte[10000000];
FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open);
BinaryReader TheFileBinary = new BinaryReader(TheFileStream);

for (int i = 0; i < TheFileStream.Length; i++) {
    FileArray = TheFileBinary.ReadBytes(10000000);
    // I call a function here
    if (TheFileStream.Position == TheFileStream.Length)
        break;
}

但是,我不希望修复数组大小,因为如果我将其设置为1000000(作为示例),则内存大小较小的其他计算机可能会遇到问题。 我需要找到每台机器的内存大小的空闲大小,如何根据可用的未分配内存空间动态设置数组大小,我可以将它放在byteArray中?

我注意到Arraysize越大,读取的速度越快,所以我也不想让它太小。 我非常感谢你的帮助。

3 个答案:

答案 0 :(得分:0)

如果你真的担心空间,那么使用一个简单的List,一次读取流的块(比如1024),并调用列表上的AddRange方法。完成后,在列表上调用ToArray,现在你有一个正确大小的字节数组。

List<byte> byteArr = new List<byte>();
byte[] buffer = new byte[1024];
int bytesRead = 0;
using(FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open))
{
    while((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
        byteArr.AddRange(buffer);
}
buffer = byteArr.ToArray();
// call your method here.

编辑:对于较大的文件,最好以块的形式读取它。你当然可以随意使用缓冲区大小,但1024通常是一个很好的起点。读取整个文件最终会使内存变为DOUBLE,因为您还必须处理内部读取缓冲区(就在您自己的缓冲区之上)。将读取分解为块只需要FileStream.Length + <buffer size>个内存而不是FileStream.Length * 2。请记住一些事情......

byte[] buffer = null;
using(FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open))
{
    buffer = new byte[TheFileStream.Length];
    int offset = 0;
    while((bytesRead = stream.Read(buffer, offset, 1024)) > 0)
        offset += bytesRead;
    // Or just TheFileStream.Read(buffer, 0, buffer.Length) if it's small enough.
}

答案 1 :(得分:0)

FileStream跟踪文件中的字节数。只需使用Length属性。

FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open);
BinaryReader TheFileBinary = new BinaryReader(TheFileStream);
byte[] FileArray = TheFileBinary.ReadBytes(TheFileStream.Length);

好的,重新阅读这个问题,并最终发现它的一部分是一个问题,“我怎么能知道免费的未分配的内存空间,所以我可以把它放在byteArray中”。无论如何,我建议你看看this question along with its highest rated comment

答案 2 :(得分:0)

您可以使用WMI检索Win32_OperatingSystem class的实例,并根据FreePhysicalMemoryTotalVisibleMemorySize属性进行内存计算:

static ulong GetAvailableMemoryKilobytes()
{
    const string memoryPropertyName = "FreePhysicalMemory";

    using (ManagementObject operatingSystem = new ManagementObject("Win32_OperatingSystem=@"))
        return (ulong) operatingSystem[memoryPropertyName];
}

static ulong GetTotalMemoryKilobytes()
{
    const string memoryPropertyName = "TotalVisibleMemorySize";

    using (ManagementObject operatingSystem = new ManagementObject("Win32_OperatingSystem=@"))
        return (ulong) operatingSystem[memoryPropertyName];
}

然后将任一方法的结果传递给这样的方法,以将读缓冲区的大小扩展到本地机器的内存:

static int GetBufferSize(ulong memoryKilobytes)
{
    const int bufferStepSize = 256;       // 256 kilobytes of buffer...
    const int memoryStepSize = 128 * 1024;// ...for every 128 megabytes of memory...
    const int minBufferSize = 512;        // ...no less than 512 kilobytes...
    const int maxBufferSize = 10 * 1024;  // ...no more than 10 megabytes
    int bufferSize = bufferStepSize * ((int) memoryKilobytes / memoryStepSize);

    bufferSize = Math.Max(bufferSize, minBufferSize);
    bufferSize = Math.Min(bufferSize, maxBufferSize);

    return bufferSize;
}

显然,对于每128 MB RAM,将缓冲区大小增加256 KB似乎有点傻,但这些数字只是如果您真的想要这样做可以扩展缓冲区大小的示例。除非你一次阅读很多很多文件,担心几百千字节或几兆字节的缓冲区可能比它的价值更麻烦。您可能最好只是通过基准测试来查看哪个大小的缓冲区提供了最佳性能(可能不需要像您想象的那么大)并使用它。

现在您只需更新代码即可:

ulong memoryKilobytes =
    GetAvailableMemoryKilobytes();
    // ...or GetTotalMemoryKilobytes();
int bufferSize = GetBufferSize(memoryKilobytes);

using (FileStream TheFileStream = new FileStream(FilePath.Text, FileMode.Open))
{
    byte[] FileArray = new byte[bufferSize];
    int readCount;

    while ((readCount = TheFileBinary.Read(FileArray, 0, bufferSize)) > 0)
    {
        // Call a method here, passing FileArray as a parameter
    }
}