【问题标题】:Best way to read a short array from disk in C#?在 C# 中从磁盘读取短数组的最佳方法?
【发布时间】:2020-05-21 19:08:26
【问题描述】:

我必须在磁盘上写入 4GB 短 [] 数组,因此我找到了一个写入数组的函数,我正在努力编写从磁盘读取数组的代码。我通常用其他语言编写代码,所以如果我的尝试到目前为止有点可悲,请原谅我:

using UnityEngine;
using System.Collections;
using System.IO;

public class RWShort : MonoBehaviour {

    public static void WriteShortArray(short[] values, string path)
    {
        using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
        {
            using (BinaryWriter bw = new BinaryWriter(fs))
            {
                foreach (short value in values)
                {
                    bw.Write(value);
                }
            }
        }
    } //Above is fine, here is where I am confused: 


    public static short[] ReadShortArray(string path) 
    {
        byte[]  thisByteArray= File.ReadAllBytes(fileName);
        short[] thisShortArray= new short[thisByteArray.length/2];      
                for (int i = 0; i < 10; i+=2)
                {
                    thisShortArray[i]= ? convert from byte array;
                }


        return thisShortArray;
    }   
}

【问题讨论】:

  • 您可能只读取所有字节和convert them to short,但 4gig 的数据很多!可能有内存问题。
  • 我以前从未在 C# 中看到过这种变量声明:thisShort : short[] = new short[];
  • 嗨,对不起,我解决了这个问题。这是一些音频分析数据,需要 20-30 分钟来计算,所以如果我可以将它保存到磁盘,我可以节省时间来研究它。它是 50*44100*600 短值。
  • 第二个代码不会编译,因为没有返回任何内容,也没有从读取中存储任何内容。该代码试图将输入分成两个相等的部分,但如果不是 4 的倍数,您将有一个具有奇数字节的左半部分和右半部分,并且读取最后一个短 (int16) 也将不起作用。
  • 我认为与其依赖数组的长度,不如使用while (fs.Position &lt; fs.Length)。我也会切换到LinkedList&lt;short&gt;,这样我就不必分配 4GB 的连续内存。 LinkedList 保持指向下一个元素/项的指针,因此内存分配不需要是连续的。

标签: c# filestream binarywriter


【解决方案1】:

Shorts 是两个字节,所以你每次必须读入两个字节。我还建议您使用这样的yield return,这样您就不会试图一次性将所有内容都拉入内存。虽然如果你需要所有的短裤对你没有帮助..我猜这取决于你在做什么。

void Main()
{
    short[] values = new short[] {
        1, 999, 200, short.MinValue, short.MaxValue
    };

    WriteShortArray(values, @"C:\temp\shorts.txt");

    foreach (var shortInfile in ReadShortArray(@"C:\temp\shorts.txt"))
    {
        Console.WriteLine(shortInfile);
    }
}

public static void WriteShortArray(short[] values, string path)
{
    using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write))
    {
        using (BinaryWriter bw = new BinaryWriter(fs))
        {
            foreach (short value in values)
            {
                bw.Write(value);
            }
        }
    }
}

public static IEnumerable<short> ReadShortArray(string path)
{
    using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
    using (BinaryReader br = new BinaryReader(fs))
    {
        byte[] buffer = new byte[2];
        while (br.Read(buffer, 0, 2) > 0)
            yield return (short)(buffer[0]|(buffer[1]<<8)); 
    }
}

你也可以这样定义它,利用BinaryReader:

public static IEnumerable<short> ReadShortArray(string path)
{
    using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
    using (BinaryReader br = new BinaryReader(fs))
    {
        while (br.BaseStream.Position < br.BaseStream.Length)
            yield return br.ReadInt16();
    }
}

【讨论】:

  • 嘿,谢谢!我真的很感激。我可以看到我将能够实现它,如果我现在不能运行它,我会非常惊讶。用于复杂的乐器识别,正在写一些实验室实验,数学比数据类型转换和内存管理更容易!
【解决方案2】:

内存映射文件是您的朋友,有一个MemoryMappedViewAccessor.ReadInt16 函数可以让您直接从操作系统磁盘缓存中读取类型为short 的数据。还有一个接受Int16Write() 重载。如果您正在调用需要传统 .NET 数组的函数,还有 ReadArrayWriteArray 函数。

MSDN 上的Overview of using Memory-mapped files in .NET

如果您想使用普通文件 I/O,请使用 1 或 2 兆字节的块大小和 Buffer.BlockCopy 函数在 byte[]short[] 之间移动数据,并使用 @987654332接受byte[] 的@ 函数。忘记BinaryWriterBinaryReader,忘记一次处理2 个字节。

也可以在 p/invoke 的帮助下将 I/O 直接放入 .NET 数组中,请参阅 my answer using ReadFile and passing the FileStream object's SafeFileHandle property here 但即使这没有额外的副本,它仍然不应该跟上内存 -映射ReadArrayWriteArray 调用。

【讨论】:

    猜你喜欢
    • 2012-03-26
    • 2022-06-10
    • 1970-01-01
    • 2015-05-29
    • 2019-06-02
    • 2021-08-12
    • 2020-10-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多