Как конвертировать текстовые файлы в двоичный файл эффективным способом в C # - PullRequest
0 голосов
/ 18 января 2019

Я проверил несколько методов преобразования текстовых файлов в двоичные и нашел здесь несколько ответов. Тем не менее, большинство из них смутило меня из-за совместимости Unity .NET, а также смущает структура преобразования текста в двоичный файл.

У меня есть текстовый файл (экспортированное облако точек), в котором хранятся положения точек в трехмерном пространстве и информация о цвете, например:

X Y Z colorvalues -0.680891 -90.6809 0 204 204 204 255

Я читал это, чтобы создать сетки во время выполнения с помощью скрипта, подобного этому:

 string[] buffer;

    for (int i = 0; i < Area.nPoints; i++)
    {
        buffer = sr.ReadLine().Split();

        Area.AddPoint(new Vector3(float.Parse(buffer[0]), 
        float.Parse(buffer[1]), float.Parse(buffer[2])));
    }

Это работает, но, поскольку я читаю линии и разделяю их, это довольно медленно, и у меня есть около 75 миллионов строк (точек) в моем текстовом файле. Я узнал, что могу преобразовать его в двоичный файл, и чтение будет быстрее, чем я, и это было намного быстрее. Однако, теперь преобразование в двоичную часть происходит довольно медленно, я хотел спросить вас о том, как я преобразовал.

void WriteValues()
{
    string[] buffer;

    for (int i = 0; i < numPoints; i++)
    {
        buffer = sr.ReadLine().Split();
        for (int j = 0; i < 3; i++)
        {
            wr.Write(float.Parse(buffer[j]));
        }           
    }        
    wr.Close();
}

Затем я читаю это с BinaryReader.ReadSingle(), но это занимает намного больше времени, чем чтение непосредственно из текста, потому что я снова читаю строку и разделяю ее.

Мой вопрос: могу ли я прочитать, скажем, следующие 1000 строк буферизуют его, а затем писать вместо чтения каждой строки? Будет ли это иметь значение. Если так, как я могу использовать поток один раз на каждые 1000 строк.

Кроме того, когда я преобразовал строку в двоичный файл, как я могу прочитать каждый float в строке, не разбивая строку? Заранее спасибо за любую помощь!

Я пытаюсь сделать это для визуализации облака точек в моем мобильном телефоне с помощью дополненной реальности. Поэтому я хочу выполнить сканирование, экспортировать облако точек, импортировать его в Unity и создать сетку, используя эти точки без триангуляции, но при моем первоначальном подходе его импорт занимает 15-18 минут. После преобразования в двоичный файл это займет не более 3 минут, что нормально. Однако на этот раз преобразование в двоичный файл занимает много времени:)

Ответы [ 3 ]

0 голосов
/ 18 января 2019

Итак, достаточно быстрый способ чтения - с использованием буферизованного потока файлов. Без анализа с плавающей запятой чтение занимает 14 секунд на моей машине .... 74 секунды с разбором с плавающей запятой (я только что подвел итог, так как у меня нет единства, с которым можно играть)

var sw = new Stopwatch();
sw.Start();
double sum = 0;
var fs = new FileStream("demo.txt", FileMode.Open, FileAccess.Read);
using (var bs = new BufferedStream(fs))
using (var r = new StreamReader(bs))
{
    r.ReadLine();
    while (!r.EndOfStream)
    {
        var l = r.ReadLine();
        var split = l.Split();
        var x = float.Parse(split[0]);
        var y = float.Parse(split[1]);
        var z=float.Parse(split[2]);
        sum += x + y + z;
    }
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds / 1000M);
Console.WriteLine(sum);

из интереса Я также изменил код для записи данных в виде потока с плавающей точкой (в триплетах)

читать с

var sw = new Stopwatch();
sw.Start();
double sum = 0;
var fs = new FileStream("demo.bin", FileMode.Open, FileAccess.Read);
using (var bs = new BufferedStream(fs))
using (var r = new BinaryReader(bs))
{
    for (int i = 0; i < 75000000; i++)
    {
        var x = r.ReadSingle();
        var y = r.ReadSingle();
        var z=r.ReadSingle();
        sum += x + y + z;
    }
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds / 1000M);
Console.WriteLine(sum);

занимает ~ 9 секунд

просто для полноты я использовал следующий код для генерации демонстрационных файлов ..

   var random = new Random();
    File.WriteAllText("demo.txt", "X         Y        Z colorvalues\r\n");
    using (var fs = new FileStream("demo.bin", FileMode.Create, FileAccess.Write, FileShare.None))
    using (var bw = new BinaryWriter(fs))
    using (var writer = File.AppendText("demo.txt"))
    {
        for (int i = 0; i < 75000000; i++)
        {
            var x = (float) random.NextDouble() * 200;
            var y = (float) random.NextDouble() * 200;
            var z = (float) random.NextDouble() * 200;
            var c = Enumerable.Range(0, 4).Select(n => random.Next(0, 255)).ToArray();
            writer.WriteLine($"{x} {y} {z} {c[0]} {c[1]} {c[2]} {c[3]}");
            bw.Write(x);
            bw.Write(y);
            bw.Write(z);
        }
}
0 голосов
/ 18 января 2019

Это может быть глупый вопрос, но почему бы вам не отсканировать и не сохранить напрямую в двоичный файл или файл .ply? Или даже отсканируйте и сохраните в сетку или в какую-нибудь вокселизированную сетку

Вы также можете посмотреть подход, использованный в этом проекте, особенно PlyImporter.cs

0 голосов
/ 18 января 2019

Если чтение выполняется медленно, чтение, запись в другой формат файла и последующее чтение из этого файла будут еще медленнее. Вы просто добавляете больше действий к чему-то медленному ... Возможно, вам стоит посмотреть, как изменить способ чтения из текстового файла.

Если вы не знакомы с тем, как сериализация / десериализация выполняется в C #, с использованием встроенных библиотек, вам следует начать со следующего: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/serialization/

Вот ссылка, показывающая, как реализовать двоичную сериализацию: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=netframework-4.7.2

Однако, если вы не пишете исходный файл, вам просто нужно написать собственный десериализатор (что, по сути, вы и сделали - без реализации соответствующих шаблонов .NET). Может быть, попробуйте использовать BufferedStream и посмотреть, поможет ли это, то есть .:

using (FileStream fs = File.Open(fileName, ..... ))
using (BufferedStream bs = new BufferedStream(fs))
using (StreamReader sr = new StreamReader(bs))
{
        string s;
        while ((s = sr.ReadLine()) != null)
        {
            //your code   
        }
}

Также стоит взглянуть на эту библиотеку, которая может помочь вам с этой задачей: FileHelpers - Посмотрите на этот пример: https://www.filehelpers.net/example/QuickStart/ReadFileDelimited/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...