ich für eine Lösung im Grunde bin auf der Suche, die mich um die Linien zu streamen und sie in der gleichen Datei zu ersetzen, a la Files.linesJeder Mechanismus in Java 8/NIO zum Ersetzen der Zeilen einer großen Datei, ohne sie in den Speicher zu laden?
Antwort
Jeder Mechanismus in Java 8/NIO die Linien einer großen Datei für den Ersatz ohne es in den Speicher zu laden?
Grundsätzlich keine.
Jede Änderung an einer Datei, bei der die Anzahl der Bytes zwischen den Offsets A und B geändert werden muss, kann nur durch Neuschreiben der Datei oder durch Erstellen einer neuen Datei erfolgen. In jedem Fall muss alles nach B in den Speicher geladen/gelesen werden.
Dies ist keine Java-spezifische Einschränkung. Dies ist eine Folge der Art und Weise, in der moderne Betriebssysteme Dateien darstellen, und die Low-Level-APIs (z. B. Syscall), die sie für Anwendungen bereitstellen.
Im besonderen Fall, wo man eine Zeile (oder eine Folge von Linien) mit einer Linie (oder eine Folge von Linien) von exakt die gleichen Länge ersetzt wird, dann kann man den Austausch tut entweder Random, oder durch Abbilden die Datei in den Speicher. Beachten Sie, dass der letztere Ansatz nicht dazu führt, dass die gesamte Datei in den Speicher gelesen wird.
Es ist auch möglich, Zeilen zu ersetzen oder zu löschen, während die Datei "vor Ort" aktualisiert wird (Änderung der Dateilänge ...). Ein Beispiel finden Sie in @Sergio Montoros Antwort. Bei einer Aktualisierung vor Ort besteht jedoch das Risiko, dass die Datei beschädigt wird, wenn die Anwendung unterbrochen wird. Und das beinhaltet das Lesen und Neuschreiben aller Bytes in der Datei nach dem Einfüge-/Löschpunkt. Und das bedeutet, sie in den Speicher zu laden.
Es gab einen Mechanismus in Java 1: RandomAccessFile
; aber jeder solche In-Place-Mechanismus erfordert, dass Sie den Start-Offset der Linie kennen, und dass die neue Linie die gleiche Länge wie die alte hat.
Andernfalls müssen Sie die Datei bis zu dieser Zeile kopieren, die neue Zeile in der Ausgabe ersetzen und dann die Kopie fortsetzen.
Sicherlich müssen Sie nicht die gesamte Datei in den Speicher laden.
Dieser Mechanismus existiert noch. Allerdings bietet NIO eine Speicherzuordnung, die für diesen Anwendungsfall möglicherweise eine höhere Leistung bietet. – Holger
Ja.
Ein FileChannel ermöglicht zufälliges Lesen/Schreiben an jede Position einer Datei. Wenn Sie einen Puffer für den Lesezugriff haben, der lang genug ist, können Sie Zeilen ersetzen, selbst wenn die neue Zeile länger als die vorherige ist.
Das folgende Beispiel ist eine Spielzeugimplementierung, die zwei Annahmen macht: 1.) die Eingabedatei ist ISO-8859-1 Unix LF codiert und 2.) jede neue Zeile wird nie länger sein als die nächste Zeile (eine Zeile gelesen) Vorauspuffer).
Wenn Sie keine temporäre Datei erstellen können, sollten Sie diesen Ansatz mit dem natürlicheren Stream in -> stream out vergleichen, da ich nicht weiß, welche Leistung ein drehendes Laufwerk Ihnen für einen Algorithmus bietet, der sich ständig weiterentwickelt rückwärts in einer Datei.
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import static java.nio.file.StandardOpenOption.*;
import java.io.IOException;
public class ReplaceInFile {
public static void main(String args[]) throws IOException {
Path file = Paths.get(args[0]);
ByteBuffer writeBuffer;
long readPos = 0l;
long writePos;
String line_m;
String line_n;
String line_t;
FileChannel channel = FileChannel.open(file, READ, WRITE);
channel.position(0);
writePos = readPos;
line_m = readLine(channel);
do {
readPos += line_m.length() + 1;
channel.position(readPos);
line_n = readLine(channel);
line_t = transformLine(line_m)+"\n";
writeBuffer = ByteBuffer.allocate(line_t.length()+1);
writeBuffer.put(line_t.getBytes("ISO8859_1"));
System.out.print("replaced line "+line_m+" with "+line_t);
channel.position(writePos);
writeBuffer.rewind();
while (writeBuffer.hasRemaining()) {
channel.write(writeBuffer);
}
writePos += line_t.length();
line_m = line_n;
assert writePos > readPos;
} while (line_m.length() > 0);
channel.close();
System.out.println("Done!");
}
public static String transformLine(String input) throws IOException {
return input.replace("<", "<").replace(">", ">");
}
public static String readLine(FileChannel channel) throws IOException {
ByteBuffer readBuffer = ByteBuffer.allocate(1);
StringBuffer line = new StringBuffer();
do {
int read = channel.read(readBuffer);
if (read<1) break;
readBuffer.rewind();
char c = (char) readBuffer.get();
readBuffer.rewind();
if (c=='\n') break;
line.append(c);
} while (true);
return line.toString();
}
}
- 1. Effizientes Laden einer großen Mat in den Speicher in OpenCV
- 2. Gibt es eine schnellere Möglichkeit, in einer großen Datei zu suchen, ohne sie in den Speicher zu laden?
- 3. Swift: Laden einer großen Videodatei (über 700MB) in den Speicher
- 4. Entfernen Sie doppelte Zeilen aus einer großen Datei in Python
- 5. So lesen Sie bestimmte Zeilen einer großen CSV-Datei
- 6. Lesen der ersten N Zeilen in einer Datei, ohne sie zu öffnen (Python)
- 7. Suchen und Ersetzen von einer großen Datei
- 8. Inhalt in einer gzip-Datei ersetzen, ohne es zu entpacken
- 9. Powershell bekommen Anzahl der Zeilen der großen (großen) Datei
- 10. wie eine große komprimierte Datei in Python zu lesen, ohne alles im Speicher zu laden
- 11. ersetzen Strings mit Sonderzeichen in einer großen Datei mit sed
- 12. Mach Pager laden Datei in den Speicher in mmap Datei
- 13. Ersetzen Sie Text in einer Datei mit Stream-Java 8
- 14. Bash - Ersetzen kleiner Linien in einer großen Textdatei effizient
- 15. Lade Bytearray der Datei in den Speicher
- 16. Verwenden von WWW: Mechanize, um eine Datei auf die Festplatte zu laden, ohne sie zuerst in den Speicher zu laden
- 17. Schnell erste Zeile der großen Datei ersetzen
- 18. So laden Sie große Bilder in Java
- 19. Get Größe des Bildes ohne Laden in den Speicher
- 20. aus einer großen Datei lesen, ohne ganze Sache in dem Speicher geladen mit h5py
- 21. Readonly-Datenbanktabellen in den Speicher laden
- 22. Suchen und Ersetzen von Wörtern/Zeilen in einer Datei
- 23. Node.js v0.10: Ersetzen Sie bestimmte Bytes in der Datei ohne ganze Datei zu lesen
- 24. Laden RDD von Datei in den Speicher in Spark zwingen
- 25. Speicher Effiziente Methode zum Behandeln einer großen HashMap
- 26. Java Zählen Sie die Zeilen in einer Datei und in der Lage, sie später zu lesen
- 27. Ersetzen jeder 4. Zeile einer Datei durch die entsprechende Zeile in einer anderen Datei
- 28. So aktualisieren Sie eine XML-Datei, ohne die gesamte Datei im Speicher zu laden
- 29. Poll-Mechanismus in Silverlight ohne DB
- 30. Laden und spielen .mp3-Datei vom Firebase-Speicher zum Speicher
Um zu tun, was Sie vorschlagen, Ihre Datei müsste in einer Weise formatiert werden, die diese Art von Änderung ermöglicht. eine Datenstruktur.Eine flache Textdatei muss von dem Punkt, an dem Sie sie ändern, neu geschrieben werden (es sei denn, Sie ändern die Länge nicht) –
Wäre es eine Option, Shell-Befehle in einem Prozess zu verwenden? Wie bei Linux könntest du eine Art 'sed'-Befehl ausgeben ... Ich weiß, das würde Nachteile wie OS-Dependency mit sich bringen, aber wenn es deine einzige Chance ist ... – Fildor
@Fildor 'sed' funktioniert nicht * in situ *. – EJP