Ich habe verschiedene Methoden zum Konvertieren von Textdateien in Binärdateien überprüft und auch hier einige Antworten gefunden. Die meisten von ihnen haben mich jedoch aufgrund der Unity .NET-Kompatibilität verwirrt, und ich bin auch verwirrt über die Struktur, wie ich Text in Binärdateien konvertiere.

Ich habe eine Textdatei (exportierte Punktwolke), die Positionen von Punkten im 3D-Raum und Farbinformationen wie folgt enthält:

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

Ich habe dies gelesen, um zur Laufzeit Netze mit einem Skript wie dem folgenden zu erstellen:

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

Dies funktioniert, aber da ich Zeilen lese und teile, ist es ziemlich langsam und ich habe ungefähr 75 Millionen Zeilen (Punkte) in meiner Textdatei. Ich fand heraus, dass ich es in Binär konvertieren kann und das Lesen schneller sein würde, was ich tat, und es war viel schneller. Jetzt ist die Konvertierung in einen Binärteil jedoch ziemlich langsam. Ich wollte Sie nach der Art und Weise fragen, wie ich konvertiert habe.

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

Dann habe ich es mit BinaryReader.ReadSingle() gelesen, aber das dauert viel länger als das direkte Lesen aus dem Text, da ich die Zeile erneut gelesen und geteilt habe.

Meine Frage ist, könnte ich lesen, sagen wir, die nächsten 1000 Zeilen puffern und dann schreiben, anstatt jede Zeile zu lesen? Würde es einen Unterschied machen? Wenn ja, wie kann ich Stream einmal pro 1000 Zeilen verwenden?

Auch wenn ich eine Zeile in eine Binärdatei konvertiert habe, wie kann ich jeden Float in der Zeile lesen, ohne die Zeichenfolge zu teilen? Vielen Dank im Voraus für jede Hilfe!

Ich versuche dies zu tun, um eine Punktwolke in meinem Mobiltelefon mit Augmented Reality zu visualisieren. Ich möchte also den Scan durchführen, die Punktwolke exportieren, in Unity importieren und ein Netz erstellen, indem ich diese Punkte ohne Triangulation verwende. Bei meinem ersten Ansatz dauert der Import jedoch 15 bis 18 Minuten. Nach der Konvertierung in eine Binärdatei dauert es weniger als 3 Minuten, was in Ordnung ist. Die Konvertierung in Binärdateien nimmt diesmal jedoch viel Zeit in Anspruch :)

0
Ali Kanat 18 Jän. 2019 im 12:45

3 Antworten

Beste Antwort

Ein relativ schneller Weg zum Lesen ist also ein gepufferter Dateistream. Ohne die Float-Analyse dauert das Lesen auf meinem Computer 14 Sekunden ... 74 Sekunden mit der Float-Analyse (ich habe nur summiert, da ich keine Einheit zum Spielen habe)

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

Aus Interesse habe ich auch den Code geändert, um die Daten als Strom von Floats (in Drillingen) zu schreiben.

Lesen Sie mit

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

Dauert ~ 9 Sekunden

Der Vollständigkeit halber habe ich den folgenden Code verwendet, um Demo-Dateien zu generieren.

   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);
        }
}
1
Keith Nicholas 18 Jän. 2019 im 11:01

Das mag eine dumme Frage sein, aber warum scannen und speichern Sie nicht direkt in eine Binär- oder .ply-Datei? Oder scannen und speichern Sie sie in ein Netz oder ein voxelisiertes Netz

Sie können auch den in diesem Projekt verwendeten Ansatz nachschlagen, insbesondere PlyImporter.cs

1
Adammak 18 Jän. 2019 im 13:04

Wenn das Lesen langsam ist, wird das Lesen, Schreiben in ein anderes Dateiformat und das Zurücklesen aus dieser Datei noch langsamer. Sie fügen nur etwas hinzu, das bereits langsam ist ... Vielleicht sollten Sie sich überlegen, wie Sie die Art und Weise ändern, wie Sie aus der Textdatei lesen.

Wenn Sie nicht mit der Serialisierung / Deserialisierung in C # unter Verwendung der integrierten Bibliotheken vertraut sind, lesen Sie zunächst Folgendes: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/serialization/

Hier ist ein Link, der zeigt, wie die binäre Serialisierung implementiert wird: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.formatters.binary.binaryformatter?view=netframework-4.7.2

Wenn Sie jedoch nicht die ursprüngliche Datei schreiben, müssen Sie nur einen benutzerdefinierten Deserializer schreiben (was Sie im Wesentlichen getan haben - ohne die relevanten .NET-Muster zu implementieren). Versuchen Sie vielleicht, ein BufferedStream zu verwenden, und prüfen Sie, ob dies hilft, z.

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

Es lohnt sich auch, einen Blick auf diese Bibliothek zu werfen, die Ihnen bei dieser Aufgabe helfen kann: FileHelpers - Sehen Sie sich das an Beispiel: https://www.filehelpers.net/example/QuickStart/ReadFileDelimited/

0
Leo 18 Jän. 2019 im 10:48