Лучший способ прочитать короткий массив с диска в C#? - PullRequest
1 голос
/ 05 февраля 2020

Мне нужно записать 4ГБ короткие [] массивы на диск и с диска, поэтому я нашел функцию для записи массивов, и я пытаюсь написать код для чтения массива с диска. Обычно я пишу на других языках, поэтому, пожалуйста, прости меня, если моя попытка пока что немного патетична c:

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;
    }   
}

Ответы [ 2 ]

3 голосов
/ 05 февраля 2020

Отображение файла в памяти - это ваш друг, есть функция MemoryMappedViewAccessor.ReadInt16, которая позволит вам напрямую считывать данные типа short из дискового кэша ОС. Также перегрузка Write(), которая принимает Int16. Также ReadArray и WriteArray функции, если вы вызываете функции, которые нуждаются в традиционном массиве. NET.

Обзор использования файлов с отображением в памяти в. NET на MSDN

Если вы хотите сделать это с обычным файловым вводом / выводом, используйте размер блока 1 или 2 мегабайта и функцию Buffer.BlockCopy для массового перемещения данных между byte[] и short[] и используйте FileStream функции, которые принимают byte[]. Забудьте о BinaryWriter или BinaryReader, забудьте о том, чтобы делать 2 байта за раз.

Также возможно выполнить ввод / вывод непосредственно в массив. NET с помощью p / invoke, см. мой ответ с использованием ReadFile и передачей здесь свойства FileStream объекта SafeFileHandle Но даже если у него нет дополнительных копий, он все равно не должен идти в ногу с отображенной в память ReadArray и WriteArray звонки.

2 голосов
/ 05 февраля 2020

Шорты - это два байта, поэтому каждый раз вы должны читать два байта. Я также рекомендовал бы использовать yield return как этот, чтобы вы не пытались вытянуть все в память за один go. Хотя, если вам нужны все шорты вместе, которые вам не помогут ... зависит от того, что вы с ним делаете, я думаю.

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();
    }
}
...