C# Einen Byte Array der Länge von 64 bit erzeugen

roker002

Commander
Registriert
Dez. 2007
Beiträge
2.103
Geht das überhaupt (sieh überschrift). Ich bekomme immer eine Exception.
Es soll die gesamte Datei auf einmal komplett async eingelesenwerden. das funktioniert alles bei kleineren Dateien...
Ich habe eine Datei ausprobiert deren Länge "2.230.887.681" Byte lang ist und es zieht nicht. Alles was über 2 Gb groß ist kann nicht mittels Byte Array alloziert werden.

Das Programm wurde mit 64 Bit kompliliert und basiert auf .NET 4.0, das system hat 8GB Ram übrig

Habe lange gesucht wie man einen Byte Array mit 64 Bit größe alloziert, aber bis jetzt habe ich nichts gefunden... außer eine Sache. Man kann einen Byte Array mit 64 Bit allozieren aber nur über Auslagerungdatei. Dieses Verfahren ist zu langsam, da die Daten auf die Festplatte geschrieben werden...

Wie machen eigentlich andere 64 Bit Programme, wie z.B. bei Videobearbeitung oder 7z?
 
1.) Dateien liest man normalerweise nur dann auf einmal ein, wenn die maximale Größe auf ein paar MB begrenzt ist. Einfach so 2GB auf einmal zu verschleudern ist sehr schlechter Stil. Das setzt schon einmal mindestens 8GB RAM voraus. Wenn die Datei einmal 10GB ist, dann kannst du schon minestens 16GB verbauen, wenn nicht 32GB notwendig sind.

2.) Du könntest ja mehrere Arrays anlegen und diese als Liste verwalten. Du liest z.B. 64KB ein, stopfst die 64KB in die Liste, liest wieder 64KB ein usw. Da kannst du dann auch einfach per Index zugreifen.
 
roker002 schrieb:
Wie machen eigentlich andere 64 Bit Programme, wie z.B. bei Videobearbeitung oder 7z?
Ob 64 Bit oder nicht, solche Programme lesen nur das ein, was sie gerade brauchen und schreiben das Ergebnis gleich weg anstatt alles im Speicher zu halten. Bildbearbeitungsprogramme wären hier die Ausnahme.
 
Die Größe eines Objekts (was Arrays ja auch sind) ist durch die CLR auf ca. 2 GB (ein bisschen weniger) begrenzt. D. h. kein CLR-Objekt kann größer als 2 GB sein.
In unmanaged Code hingegen kannst du natürlich mit z. B. "malloc" theoretisch soviel Speicher reservieren wie du willst (dank Auslagerungsdatei sogar mehr als RAM vorhanden ist).

Wie bereits gesagt ist es meist eh eine schlechte Idee solche Datenmengen "auf einen Rutsch" einzulesen. In der Regel ist das Blockweise auslesen (bei "richtiger" Blockgröße) auch ausreichend.
 
Ich weiss das es schlecht ist. Es geht wesentlich darum eine sehr große Datei in mehrere kleinere Dateien zu trennen. Nach einigen Test gab es eindeutiges Ergebnis, dass es schneller wäre eine Datei komplett einzulesen. Auf eine SSD (2 GB Dateigröße) kann der Code die Datei in x verschiedene Teile braucht der Code ~ 1 Sekunde für die Aufteilung. Auf eine normale HDD 3-6 sekunden. Wenn ich die Datei Stückweise verarbeite, dann kann ich nicht async anwenden... da es einfach keinen Sinn hat mehrere Threads anzuwenden. Wie viel Speicher drauf gehen kann/darf ist ehe nebensächlich.

Nagut, also es geht wirklich nicht.

Danke
 
ein array mit 64bit größe erzeugen...
naja, das ist deshalb schwer, da die Länge des Arrays, die Anzahl der Elemente wiedergibt.
was du willst, ist, dass die Datenmenge die im Array lagert, durch einen Integer32 nicht mehr bestimmt werden kann.
ein 64bit array?
sehrwohl: 64bit = 8 byte, das entspräche:
byte[] vierundsechzig = new byte[8];
schon nimmt die anzahl an bits in dem Array 64 an.
Jetzt zu dem Vorhaben: es sollen so viele Daten im Array gespeichert werden, dass die anzahl an bits nicht mehr durch eine 32bit binärzahl angegeben werden kann. Es müssen also 2.147.483.647 (signed int32 maxValue) +1 bits gespeichert werden, das sind 268 435 456 bytes.
byte[] b = new byte[268435456];
bittesehr, dieses array ist so lang, dass die datenlänge nicht per 32bit zahl bestimmt werden kann.
Allerdings sollte man immer beachten, dass man in c# nicht mehr als 2gb ram pro programm(/thread?/prozess?) beanspruchen kann, egal wieviel bit

MfG
Damon
 
roker002 schrieb:
Auf eine SSD (2 GB Dateigröße) kann der Code die Datei in x verschiedene Teile braucht der Code ~ 1 Sekunde für die Aufteilung. Auf eine normale HDD 3-6 sekunden.
Wie meinst du jetzt 1s? Das Schreiben dauert doch sicher länger als 1s?
Was du natürlich nicht machen solltest ist, dass du die Daten wirklich byteweise liest. Reservier dir einen Puffer (paar KB, evtl. auch MB. Muss man austesten), lies das jeweils und schreibs dann weg. Unter Umständen kann man das Schreiben auch über nen extra Thread machen.
Eine andere Möglichkeit wäre, mal nach einer mmap-Library zu gucken bzw. System.IO.MemoryMappedFiles.MemoryMappedFile zu nutzen.
 
roker002 schrieb:
Ich weiss das es schlecht ist. Es geht wesentlich darum eine sehr große Datei in mehrere kleinere Dateien zu trennen. Nach einigen Test gab es eindeutiges Ergebnis, dass es schneller wäre eine Datei komplett einzulesen. Auf eine SSD (2 GB Dateigröße) kann der Code die Datei in x verschiedene Teile braucht der Code ~ 1 Sekunde für die Aufteilung. Auf eine normale HDD 3-6 sekunden. Wenn ich die Datei Stückweise verarbeite, dann kann ich nicht async anwenden... da es einfach keinen Sinn hat mehrere Threads anzuwenden. Wie viel Speicher drauf gehen kann/darf ist ehe nebensächlich.

Nagut, also es geht wirklich nicht.

Danke


Ermittle einfach die Dateigröße, teile sie in Happen auf (vielleicht Häppchen in der Größe wie deine Zieldateien sein sollen) und erstelle dir eine Prozedur die als Eingabeparameter den zu lesenden Dateinamen, den Zieldateinamen und die Start- und Endposition des zu lesenden Happens annimmt.
Dann erstellst du dir die nötige Anzahl Threads und lässt jeweils die Funktion laufen. So liest du die gesamte Datei parallel komplett ein und kannst auch gleich die gesplitteten Bereiche wegschreiben.
 
@bernig
Lesen und schreiben erfolgt asynchron. Die Bruchstelle zu finden, passiert aber synchron, da es natürlich abgeglichen werden muss, ob die richtige Bruchstelle gefunden wurde und ob die Folgedatei auch an der richtige Stelle aufgeteilt wird.

@MacGyver
wäre auch meine Überlegung. Der Code liegt aber vorerst auf Eis, da man zusätzlich noch die Zeit zum Mod. und testen braucht, was der Kunde noch nicht machen will. In dem Fall muss man aber das Finden der Bruchstelle auch asynchron machen, was zusätzliche Tests und Durchläufe benötigt....

Asynchron nach der Bruchstelle zu suchen, wird auch einen + für Performance bedeuten.
 
Im Prinzip ist es doch ganz einfach und man muss auch nichts suchen.

Du hast beispielsweise ne Datei von 1.000.000 Bytes und teilst die in 5 Teile auf. Somit ist jedes Teil 200.000 Bytes groß. Bis hierhin mußt du überhaupt nichts mit der Datei machen, außer natürlich die Größe zu bestimmen. Dann erstellst du 5 Threads, die jeweils ein und die selbe Methode abarbeiten. Die Methode nimmt den Quelldateinamen, die errechnete Startposition, die errechnete Endposition und den Zieldateinamen an. In der Prozedur wird die Quelldatei geöffnet, die Datenmenge gelesen und in die Zieldatei geschrieben und die Quelldatei wieder geschlossen.
Ein Seek, ob synchron oder asynchron ist nicht nötig.

Die 5 Threads schmeißt du in den Threadpool von .NET und wartest bis sie alle abgearbeitet sind.
 
Zurück
Oben