2016-06-24 37 views
1

Beim Debuggen eines Problems bei der Arbeit habe ich festgestellt, dass versucht wird, einen MapedByteBuffer nach dem Öffnen eines FileOutputStream zu verwenden file (die Datei, aus der der MappedByteBuffer durch einen Aufruf von FileChannel.map() erstellt wurde) verursacht die folgende Ausnahme:Das Lesen von einem java.nio.MappedByteBuffer, wenn ein FileOutputStream für die zugeordnete Datei geöffnet ist, verursacht einen "unsafe memory access" Fehler

"Ausnahme im Thread" main "java.lang.InternalError: ein Fehler ist aufgetreten eine unsichere Speicherzugriffsoperation ".

Hier ist ein kleines Codebeispiel ich zusammen warf, die konsequent die Ausnahme auslöst:

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.nio.ByteBuffer; 
import java.nio.channels.FileChannel; 

public class SomeClass { 
    // make sure the test file is at least this size, or you'll get a "cannot 
    // extend file to required size" exception when creating the buffer 
    private static int bufferSize = 10; 

    public static void main(String[] args) throws Exception { 
     File file = new File("/tmp/someFile"); 

     FileInputStream fis = new FileInputStream(file); 
     ByteBuffer bb = getByteBuffer(fis); 

     // If you comment this out, the error goes away. 
     new FileOutputStream(file); 

     bb.get(); 
    } 

    private static ByteBuffer getByteBuffer(FileInputStream fis) throws Exception { 
     return fis.getChannel().map(FileChannel.MapMode.READ_ONLY, 
      fis.getChannel().position(), bufferSize); 
    } 
} 

Der obige Code führt konsequent die vorgenannte Ausnahme ausgelöst werden. Der Fehler tritt bei dem Befehl "bb.get()" auf und tritt nicht auf, wenn ich den Code, der den FileOutputStream öffnet, auskommentiere.

Es scheint mir, dass der Fehler passiert, weil der ByteBuffer, den ich .get() aufrufen, auf die gleiche Datei gespeichert ist, die ich an den FileOutputStream übergeben habe. Ich vermute, dass es eine interne Sicherheitsmaßnahme gibt, die verhindert, dass im Speicher abgelegte Dateien gelesen werden, wenn die Datei geöffnet wird, aber ich kann nicht herausfinden, was der Grund dafür ist.

Was ist das Besondere an Memory-mapped ByteBuffers, das verhindert, dass eine Leseoperation zulässig ist, wenn ein geöffneter FileOutputStream in der Datei vorhanden ist? Ich bin sehr daran interessiert, die Interna dieser Ausnahme zu verstehen. Was mich auch verwirrt, ist, dass es scheinbar kein ähnliches Problem gibt, einen FileInputStream zu öffnen und davon zu lesen, wenn ein FileOutputStream für die gleiche Datei geöffnet ist, obwohl dies im Wesentlichen sehr funktional ähnlich sein sollte (Lesen von einer bereits existierenden Datei) zum Schreiben geöffnet).

Antwort

2

Wenn Sie eine Speicherzuordnung erstellen, ordnen Sie einen Bereich einer Datei in den Speicher zu.

Wenn Sie FileOutputStream verwenden, schneiden Sie die Datei ab und der von Ihnen zugeordnete Speicherbereich existiert nicht mehr.

Wenn Sie die Datei nicht abschneiden, hat sie die Größe, die Sie beim Ausführen des Mappings angegeben haben.

+2

Sie haben absolut Recht - das ist definitiv was passiert. Ich habe einen weiteren Schnelltest gemacht, bei dem ich das "append" -Flag an FileOutputStream übergeben habe und das Problem nicht mehr auftritt. –