RandomAccessFile, FileChannel, MappedByteBuffer

Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo!

Wir haben hier folgendes Problem, was uns nun schon seit drei Tagen aufhält.

Wir wollen einen bestimmten Text(teil) mit fest definierbarer Länge in eine bestimmte Position schrieben. Der Inhalt an dieser Position soll dann um das Eingefügte verschoben werden. Somit wollen wir ein Überschreiben verhindern.

Wir arbeiten mit den RandomAccessFile Objekten. Dies ist auch so fest, basiert doch alles restliche darauf (und funktioniert). Auf diesem RAF Objekt machen wir einen FileChannel auf. Dieser ist Grundlage für einen MappedByteBuffer.

Unserern Überlegungen nach gibt es drei Teile in dem Textdokument:

1) Der Teil, der vor dem eingefügten liegt
2) Der eingefügte Text
3) Der Schlussteil, der nach dem eingefügten Text liegt und um eine gewisse Anzahl an Bytes verschoben werden muss.

Jemand eine Idee?

Mit dem bisherigen Code überschreiben wir den Inhalt leider immer! :-(
 
K

Körby

Gast
Wie wäre e wenn, wenn ihr den bisherigen Code hier einfügt, dann kann man euch vielleicht sagen, was ihr an eurem Code ändern müsst.
 
G

Guest

Gast
Unser bisheriger Code inklusive einiger ;) Auskommentierungen, da wir nicht genau wissen, wo es harkt ;)

Code:
public RandomAccessFile copyUsingOffset(RandomAccessFile randomAccessFile, int sourcePosition, int lengthOfOffset, int targetPosition) {
			Vector<Object> returnResults = new Vector<Object>();
			
			long sourcePositionL = (long) sourcePosition;
			long lengthOfOffsetL = (long) lengthOfOffset;
			long targetPositionL = (long) targetPosition;
			String fileContent = "";
			
			FileChannel fileChannel = convertToChannelRandom(randomAccessFile);
			
			
			try {
				fileContent = getFileContent(fileChannel);
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			prepareMatcher(randomAccessFile);
			
			int lines = 0;
			
			ByteBuffer byteBuffer = null;
						
			try {
				System.out.println("RegExEngine says: copyUsingOffset is sourcePositionL = " + sourcePositionL);
				System.out.println("RegExEngine says: copyUsingOffset is lengthOfOffsetL = " + lengthOfOffsetL);
				System.out.println("RegExEngine says: copyUsingOffset is targetPositionL = " + targetPositionL);
				System.out.println("RegExEngine says: copyUsingOffset is fileChannel.size() = " +fileChannel.size());
				//TODO
				MappedByteBuffer mbbPreContentToCopy = fileChannel.map(MapMode.READ_ONLY , 0, targetPositionL);
				MappedByteBuffer mbbTheContentToCopy = fileChannel.map(MapMode.READ_ONLY, targetPositionL, lengthOfOffsetL);
				MappedByteBuffer mbbPostContentToCopy = fileChannel.map(MapMode.READ_ONLY , targetPositionL+lengthOfOffsetL, fileChannel.size()-targetPositionL);
			
				MappedByteBuffer mbb = new MappedByteBuffer();
				mbb.allocate(mbbPreContentToCopy.capacity() + mbbTheContentToCopy.capacity() + mbbPostContentToCopy.capacity());
				
		
				ByteBuffer[] byteBufferArray = {mbbPreContentToCopy,mbbTheContentToCopy,mbbPostContentToCopy};
				
				fileChannel.write(mbbTheContentToCopy, 0);
				fileChannel.write(mbbPostContentToCopy, targetPositionL+lengthOfOffsetL);
				fileChannel.write(mbbPostContentToCopy,0);
			
				//fileChannel.write(byteBufferArray);
				//fileChannel.write(byteBufferArray, 0, (int)fileChannel.size()+lengthOfOffset);
				
				
				//fileChannel.transferFrom(fileChannel.position(positionSourceLong), positionTargetLong, textToCopyLong);
				//byteBuffer =  fileChannel.map(MapMode.READ_WRITE , positionTargetLong, fileChannel.size());
				
				
			} catch (IOException e) {
				e.printStackTrace();
				System.out.println("RegExEngine says: "+e.getMessage());
			} 
			try {
				System.out.println("FileChannel is open? "+fileChannel.isOpen());
				fileChannel.close();
				System.out.println("FileChannel is open? "+fileChannel.isOpen());
			} catch (IOException e) {
					e.printStackTrace();
			}
			fileChannel = null;
			return randomAccessFile;
		}
 
K

Körby

Gast
Da ich selbst noch Anfänger bin, weiß ich nicht genau was die von euch verwendeten Methoden machen oder ob es eine einfache möglichkeit gibt, euer Problem zu lösen.
Aber ich hab mal eine einfache Methode erstellt, die man verwenden könnte.

Code:
public String einfuegen(int i, String text, String ein)
	{
		int hilfe = text.length() + ein.length() + 1;
		char[] c = new char[hilfe];
		int hilfe2 = 0;
		int t = 0;
		while (text.charAt(i) != ' ')
		{
			i++;
		}
		for (int j = 0; j < hilfe; j++)
		{
			if (j == i)
			{
				c[hilfe2] = ' ';
				hilfe2++;
				for (int z = 0; z < ein.length(); z++)
				{
					c[hilfe2] = ein.charAt(z);
					hilfe2++;
				}
			}
			else if (t < text.length())
			{
				c[hilfe2] = text.charAt(t);
				hilfe2++;
				t++;
			}
		}
		text = "" + c[0];
		for (int j = 1; j < hilfe2; j++)
		{
			text = text + c[j];
		}
		return text;
	}

Es wird bei dieser Methode erst die Stelle übergeben, an der eingefügt werden soll, dann der ürsprüngliche Text als String und anschliesend was eingefügt werden soll, ebenfalls als String.
Am Ende wird der neue Text als String zurückgegeben.

Eigentlich sollte es möglich sein, den inhalt eines Files oder FileChannels in einen String zu schreiben und dann an die Methode zu übergeben.

Bei meiner Methode wird zu dem nächsten Leerzeichen gegangen und dort der einzufügende Text eingefügt.
 

lhein

Top Contributor
@Körby
Der Grund, warum hier mit FileChannel und MappedByteBuffer gearbeitet wird ist, daß man performant sein will. Dein Vorschlag in allen Ehren, aber ich glaub kaum, daß der in diesem Fall hilfreich ist.

lr
 
K

Körby

Gast
@LR
Ich weiß das mein Vorschlag nicht der beste ist und man da dann Performence verlieren dürfte, aber es hat bisher leider keiner einen anderen Vorschlag gemacht.
Mir wäre eine schlechte Performence lieber, als das mein Programm überhaupt nicht läuft.

Zumindestens bis man eine bessere Lösung hat, kann man sowas verwenden, wenn man ein Programm möglichst schnell lauffähig haben muss.
 

lhein

Top Contributor
Also im Prinzip versteh ich das ganze Problem hier noch nicht bis ins letzte Detail.

Du hast eine sehr große Text-Datei (weil nur dann macht es Sinn, die Datei direkt zu mappen).
Diese Datei beinhaltet 3 Teile...einen Part vor dem zu kopierenden Teil, den zu kopierenden Teil und den Teil nach dem zu kopierenden Teil. Da frage ich mich schonmal, was wird hier wohin kopiert?
Fakt ist, daß die MappedByteArrays einen bestimmten Bereich des FileChannels direkt im Memory abbilden. Der Zugriff darauf wird über ein Flag geregelt (READ_ONLY / READ_WRITE / PRIVATE).

Da Du hier überall mit READ_ONLY zugreifst, ist die Änderung direkt im File mal ausgeschlossen. Ansonsten käme mir hier die folgende Idee (muss man mal nachprüfen, ob das so geht). Mach einen READ_ONLY Bereich auf, der bis zu dem zu kopierenden Bereich gilt (eigentlich brauchst Du den Bereich nicht). Mach einen zweiten Bereich READ_WRITE auf, der von da bis zum Ende geht + die zu erwartende Mehranzahl an Bytes durch das kopieren. (kann sein, daß das nicht geht)
Jetzt kannst du direkt in dem Buffer rummolchen um das gewünschte Resultat zu bekommen. Die Funktionsweise dieser Logik ist übrigens betriebssystemspezifisch. Andere Dateien, die dieses File beobachten, bekommen evtl. Änderungen nicht unbedingt mit.

Grundsätzlich würde ich wirklich überlegen, ob Du hier ein direktes File2Memory Mapping brauchst. Das lohnt sich wie gesagt erst bei sehr großen Files. Wenn es kleine Dateien sind, dann lad sie in den Memory und bastel Dir den Output wie Du es brauchst.

lr
 

Wildcard

Top Contributor
LR hat gesagt.:
Das lohnt sich wie gesagt erst bei sehr großen Files. Wenn es kleine Dateien sind, dann lad sie in den Memory und bastel Dir den Output wie Du es brauchst.
Ich merke schon, 'sehr groß' ist ein dehnbarer Begriff. Für mich sind wenige kb noch nicht unbedingt 'sehr große' Dateien :wink:
 

lhein

Top Contributor
Wildcard hat gesagt.:
LR hat gesagt.:
Das lohnt sich wie gesagt erst bei sehr großen Files. Wenn es kleine Dateien sind, dann lad sie in den Memory und bastel Dir den Output wie Du es brauchst.
Ich merke schon, 'sehr groß' ist ein dehnbarer Begriff. Für mich sind wenige kb noch nicht unbedingt 'sehr große' Dateien :wink:

Erleuchte mich mit Deinem Wissen, denn ich kann grad keine Stelle entdecken, wo von wenigen Kilobyte die Rede ist. Aber vielleicht ist mein Kaffeepegel auch noch nicht hoch genug ;)

lr
 

Wildcard

Top Contributor
Die API schreibt das:
For most operating systems, mapping a file into memory is more expensive than reading or writing a few tens of kilobytes of data via the usual read and write methods. From the standpoint of performance it is generally only worth mapping relatively large files into memory.
Meine ganz persönliche Grenze setze ich für gewöhnlich bei einer erwarteten Dateigröße von 500KiB, oder mehr. Von sehr großen Dateien kann man da aber noch nicht wirklich sprechen (die fangen bei mir bei 500 MiB oder 1 GiB an).
 

lhein

Top Contributor
@Gast:

Ich hab es mal versucht nachzuvollziehen. Der folgende Code funktioniert bei mir:

Code:
    private static void copyInFile(     RandomAccessFile randomAccessFile,
                                        int sourcePosition, 
                                        int lengthOfOffset,
                                        int targetPosition)
        {
        FileChannel fileChannel = randomAccessFile.getChannel();

        try
            {
            MappedByteBuffer mbbPreContentToCopy = fileChannel.map(MapMode.READ_ONLY, 0, (long)targetPosition);

            long fileSize = fileChannel.size();
            
            long size = fileSize
                      - (long)targetPosition 
                      + (long)lengthOfOffset; 
            
            MappedByteBuffer mbbTheContentToCopy = fileChannel.map(MapMode.READ_WRITE, (long)targetPosition, size);

            
            // read the old content
            byte[] data = new byte[(int)fileSize - targetPosition];
            mbbTheContentToCopy.get(data);
            
            // read the copy content
            byte[] copycontent = new byte[lengthOfOffset];
            mbbPreContentToCopy.position(sourcePosition);
            mbbPreContentToCopy.get(copycontent);
            
            // rewind the buffer
            mbbTheContentToCopy.rewind();
            
            // now write to file
            mbbTheContentToCopy.put(copycontent);
            mbbTheContentToCopy.put(data);
            
            // make changes persistent and close everything
            mbbTheContentToCopy.force();
            }
        catch (IOException e)
            {
            e.printStackTrace();
            System.out.println("RegExEngine says: " + e.getMessage());
            }
        finally
            {
            try
                {
                fileChannel.close();
                randomAccessFile.close();
                }
            catch (IOException ex)
                {
                ex.printStackTrace();
                }
            }
        }

Kannst ja mal sehen, ob Du das für Deinen Fall anpassen kannst.
Der oben programmierte Ablauf funktioniert nur, wenn Du den Content im File Richtung Dateiende verschiebst. Solltest Du rückwärts verschieben wollen, dann reicht die Logik nicht aus :)

btw.: der Code ist nur ansatzweise getestet. Ich übernehme also weder Garantie noch Verantwortung.

Grüße
lr
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
M RandomAccessFile int und String gleichzeitig in einer Datei Java Basics - Anfänger-Themen 49
N Randomaccessfile Java Basics - Anfänger-Themen 2
G Wie gebe ich einen Dateipfad in RandomAccessFile an? Java Basics - Anfänger-Themen 2
S TextArea, RandomAccessFile, Apend und andere Tricks... Java Basics - Anfänger-Themen 7
R RandomAccessFile verständnis Problem Java Basics - Anfänger-Themen 10
D RandomAccessFile Java Basics - Anfänger-Themen 2
P RandomAccessFile writeInt() und writeChar() Java Basics - Anfänger-Themen 3
L RandomAccessFile liest nicht alle Zeichen Java Basics - Anfänger-Themen 3
D Erste Schritte RandomAccessFile "Leerzeichen" löschen Java Basics - Anfänger-Themen 6
F Kann RandomAccessFile Zip Datei lesen? Java Basics - Anfänger-Themen 14
B Klassen RandomAccessFile Java Basics - Anfänger-Themen 7
B Collections RandomAccessfile & Linkedlist Java Basics - Anfänger-Themen 4
M Frage zur Klasse RandomAccessFile Java Basics - Anfänger-Themen 8
cosmic Frage zu der RandomAccessFile Klasse Java Basics - Anfänger-Themen 6
K RandomAccessFile Java Basics - Anfänger-Themen 4
T RandomAccessFile - Wie schreibe ich etwas in eine txt Datei? Java Basics - Anfänger-Themen 5
C RandomAccessFile vs. Streams Java Basics - Anfänger-Themen 5
D text dateien mit RandomAccessFile manipulieren Java Basics - Anfänger-Themen 6
T RandomAccessFile und der Dateipfad Java Basics - Anfänger-Themen 2
J RandomAccessFile löschen Java Basics - Anfänger-Themen 2
M RandomAccessFile Java Basics - Anfänger-Themen 3
P Datei mit RandomAccessFile einlesen Java Basics - Anfänger-Themen 14
M RandomAccessFile schreibt Sonderzeichen vor String Java Basics - Anfänger-Themen 2
R RandomAccessFile mit anderen Streams verbinden Java Basics - Anfänger-Themen 5
J File, RandomAccessFile File wird größer Java Basics - Anfänger-Themen 8
J RandomAccessFile schreibt falsch Java Basics - Anfänger-Themen 2
G RandomAccessFile Java Basics - Anfänger-Themen 20
R RandomAccessFile Java Basics - Anfänger-Themen 4
R RandomAccessFile und ObjectoutputStream Java Basics - Anfänger-Themen 2
T RandomAccessFile erzeugt seltsame Zeichen Java Basics - Anfänger-Themen 2
P RandomAccessFile Java Basics - Anfänger-Themen 2
L RandomAccessFile und readChar readByte Java Basics - Anfänger-Themen 2
D konvertierungsprobleme bei RandomAccessFile Java Basics - Anfänger-Themen 4
L RandomAccessFile - Prob Java Basics - Anfänger-Themen 4
N RandomAccessFile(File, String) erstellt datei?! Java Basics - Anfänger-Themen 6
B RandomAccessFile Java Basics - Anfänger-Themen 12
M RandomAccessFile liest nur jeden zweiten Wert aus! Java Basics - Anfänger-Themen 8
G RandomAccessFile Java Basics - Anfänger-Themen 2
O RandomAccessFile komisch zeichen Java Basics - Anfänger-Themen 7
A RandomAccessFile Java Basics - Anfänger-Themen 7
B String in ein RandomAccessFile einfügen (bestimmte Position) Java Basics - Anfänger-Themen 4
B [Erledigt] Fehlverhalten mit File, FileInput/OutputStream und FileChannel Java Basics - Anfänger-Themen 4
brunothg Inputstream zu Filechannel Java Basics - Anfänger-Themen 6
S beim FileChannel nach byte[] :( zu doof heute :( Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben