【问题标题】:Array size based on available physical memory基于可用物理内存的数组大小
【发布时间】:2012-06-19 17:36:17
【问题描述】:

我正在尝试制作一种加密算法。 我可以毫无问题地读取文件并将其转换为字节,并将字节保存在 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(例如),其他内存大小较小的机器可能会遇到问题。 我需要找到每台机器的内存大小的 Idle 大小,如何根据空闲的未分配内存空间动态设置数组大小,以便在可以放入 byteArray 的地方使用?

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

【问题讨论】:

  • am trying to make an encryption algorithm 这可能是个错误。安全加密是hard
  • 您要求的大约 10MB 是一个很小的数量。你为什么担心这里的内存问题?你遇到问题了吗?您是否预计未来在 10MB 很多的设备上会出现特定问题?
  • (可以说)更好的方法是制作自己的 Stream。
  • 这可能是一个愚蠢的问题,但如果你想要一个动态大小的数组,为什么不使用List&lt;byte&gt;
  • 他不想要一个动态大小的数组,他想要一个大小在运行时决定的数组。

标签: c# arrays


【解决方案1】:

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

【讨论】:

  • 作者试图以最佳大小的块读取和处理文件,而这会将整个文件一次读入一个数组。此外,FileStream.Length 属性拼写错误。
【解决方案2】:

如果你真的担心空间问题,那么使用一个简单的列表,一次读取流的块(比如 1024),然后调用列表上的AddRange 方法。完成后,在 List 上调用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 通常是一个很好的起点。读取整个文件最终会使内存加倍,因为您还必须处理内部读取缓冲区,即流的大小(在您自己的缓冲区之上)。将读取分成块只需要FileStream.Length + &lt;buffer size&gt; 内存,而不是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.
}

【讨论】:

  • 您正在分块读取文件,但最终会得到一个存储在byteArraybuffer 中的整个文件的副本。作者担心内存使用,一次只希望文件的一个块在内存中。
【解决方案3】:

您可以使用 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
    }
}

【讨论】:

    猜你喜欢
    • 2018-07-27
    • 2010-12-11
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 2011-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多