Input/Output Dateiausgabe mit FileChannel merkwürdig

Vorab: Ich möchte von mehreren Rechnern auf eine gemeinsame Textdatei im Netzwerk zugreifen und jeweils den Text immer erweitern.

Dazu wäre es ratsam, den Schreibzugriff durch andere Clients zu unterbinden, solang noch Aktivität besteht.
Bislang speichere ich immer mit BufferedWriter(), FileOutputStream() & Co.
Da hab ich mir auf dem NAS mal eine Datei erzeugt, die ich von 2 Instanzen aus aus Netbeans heraus gleichzeitig beschreibe:
Mal von 0-50.000 "Vorwärts" und von 120.000 "Rückwärts" bis 0 gezählt.
Die 50.000 in der zweiten Instanz sind durchgelaufen und alle eingegangen in die Datei, bei den 120.000 der anderen hat es mir grad 2 Exeptions geworfen, weil das Netzwerk ausgelastet ist. Diese 2 Einträge fehlen dann auch (sind nur 119.998 Ergebnisse für "Vorwärts", ggü 50.000 auf "Rückwärts")
das könnte man ja noch abfangen und im Fall einer Exeption dieser Art einfach periodisch mit ner while-Schleife so oft drüber, bis der Speichervorgang abgeschlossen wurde - auf dass es nicht unendlich lange dauert ...




Daher hab ich mir als Alternative eigentlich ergoogelt, dass die Klasse FileChannel() es erlaubt, per .lock() den Schreibzugriff für anderer Clients zu verbieten, während die Datei gerade bearbeitet wird.

Am Beispiel hab ich mich orientiert bei diesen hier:
http://www.java2s.com/Tutorial/Java/0180__File/UsingaChanneltoWriteaStringtoaFile.htm

Das ist der Code, den ich hier dann ausführe:

Java:
package FileChannelModus;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
*
* @author zerstreuterprof
*/
public class LaufendSchreiben {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws InterruptedException {
        // TODO code application logic here
        int count = 0;
        FileChannel outChannel;
        while (count < 2) {
            count++;
            StringBuilder sb = new StringBuilder();
            Date time = Calendar.getInstance().getTime();
            DateFormat formatter = new SimpleDateFormat();
            // Format 26.04.10 18:11
            String sSimpleDateTime = (formatter.format(time));
            sb.append(sSimpleDateTime);
            sb.append("\n");

            try {

                //String phrase = new String(sb.toString());
                String phrase = new String("Test\n");

                FileOutputStream outputFile = null;
                try {
                    outputFile = new FileOutputStream("D:\\test.txt", true);
                    System.out.println("File stream created successfully.");
                } catch (FileNotFoundException e) {
                    e.printStackTrace(System.err);
                }
                outChannel = outputFile.getChannel();
                outChannel.lock();

                ByteBuffer buf = ByteBuffer.allocate(1024);

                System.out.println("New buffer:           position = " + buf.position() + "\tLimit = " + buf.limit() + "\tcapacity = " + buf.capacity());
                for (char ch : phrase.toCharArray()) {
                    buf.putChar(ch);
                }
                System.out.println("Buffer after loading: position = " + buf.position() + "\tLimit = " + buf.limit() + "\tcapacity = " + buf.capacity());
                buf.flip();
                System.out.println("Buffer after flip:   position = " + buf.position() + "\tLimit = " + buf.limit() + "\tcapacity = " + buf.capacity());
                try {
                    outChannel.write(buf);
                    outputFile.close();
                    System.out.println("Buffer contents written to file.");
                } catch (IOException e) {
                    e.printStackTrace(System.err);
                }

            } catch (Exception e) {

            }
            Thread.sleep(5000);

        }

    }
}

heraus kommt dann leider etwas mit . oder "null" durchmischtes. Je nach Texteditor ...

Screenshot 2015-10-08 18.17.03.png Screenshot 2015-10-08 18.17.16.png

Ich werde nicht ganz schlau, wie es zu dem zusätzlichen Zeichen kommt, anstatt mir einfach nur in 2 Zeilen "Test" zu schreiben.


Würde ich mit dem BufferedWriter arbeiten, hätte ich als nächstes wohl auch das Problem, sobald ich die Datei hinterher händisch mitten drin bearbeiten möchte.
Das hab ich wahrscheinlich auch so, weil ich kaum einen Texteditor finden werde, der während ich die Datei am PC geöffnet habe und bearbeite, die ganzen anderen schreibenden Anfragen blockt. Damit müsste ich sämtliche Änderungen vorsichtshalber in einem kleinen extra Programm vornehmen und die Datei dann ebenfalls mit FileChannel() sichern. Soweit so gut für mich verständlich. Das würde ich wohl hinbekommen.

Hat also jemand einen Tipp und Ahnung, was es mit dem Kauderwelsch auf sich hat?
 

JStein52

Top Contributor
Das ist die JavaDoc zu putChar:

public abstract ByteBuffer putChar(char value)

Relative put method for writing a char value (optional operation).

Writes two bytes containing the given char value, in the current byte order, into this buffer at the current position, and then increments the position by two.

Wobei ich jetzt aber auch nicht weiss was das zweite Byte soll ??

Und wenn du dir den returnwert der write-Methode anschaust sagt er auch dass er jeweils 10 Bytes schreibt und nicht 5 !!
 
public abstract ByteBuffer putChar(char value)

Relative put method for writing a char value (optional operation).

Writes two bytes containing the given char value, in the current byte order, into this buffer at the current position, and then increments the position by two.

Alternativ gibt es noch
public abstract ByteBuffer putChar(int index, char value)

Absolute put method for writing a char value (optional operation).
Writes two bytes containing the given char value, in the current byte order, into this buffer at the given index.

Hier steht nichts mit 2 Bytes und auch nicht, dass die Position um 2 erhöht wird.

für index müsste ich doch die 0 angeben, damit der Text am Anfang steht.
aber egal, welchen Wert ich angebe, die Datei bleibt dann leider leer.

Java:
                int position =1;
                for (char ch : phrase.toCharArray()) {
                    //buf.putChar(ch);
                    buf.putChar(position, ch);
                    position++;
                    position++;
                }

Sollte doch eigentlich das selbe abbilden, kommt aber gar nix bei raus.
 
anderes Beispiel:
char ch = phrase.toCharArray()[0];
buf.putChar(0, ch);

Wert des ByteBuffers ist dann immer noch java.nio.HeapByteBuffer[pos=0 lim=0 cap=1024]

anders, wenn einfach nur buf.putChar(ch); ausgeführt wird:
java.nio.HeapByteBuffer[pos=0 lim=2 cap=1024]
 
Okay, durch dieses € Zeichen wurde ich misstrauisch, ob diese Anwendung überhaupt noch korrekt arbeiten würde, wenn ich es denn schaffe, die Leerzeichen zu unterdrücken. Schließlich sind auch Sonderzeichen zu erwarten.

Folglich hab ich weiter geschaut. Die Klasse bietet noch die Möglichkeit, den Buffer mit Bytes zu befüllen. putChar(byte []).
Und schau: http://stackoverflow.com/questions/18571223/how-to-convert-java-string-into-byte

Auf byte[] komm ich ja ganz leicht, in dem ich den String in ein solches zerlegen lasse:
byte[] b = str.getBytes("UTF-8");

(Encoding-Exception abfangen)

durch buf.put(b) wandert das Array dann 1:1 direkt in den ByteBuffer hinein.

Zugegeben, die Konsole haut dann mit diesem Code eine ziemliche Scheiße raus:
쎜鱢扥敲牲牡慳獣捨桵畮湧朡℠⁉䥣捨栠⁨桡慢扥攠⁨桩楥敲爠‵㔰〰〠⃢芬갠⁦曃쎼뱲爠⁄䑩楣捨栠⁺穵畭洠⁇䝥敢扵畲牴瑳獴瑡慧朡

Die Text-Datei aber war schonmal nicht so falsch. Das €-Zeichen noch nicht korrekt, statt Umlaute wie dem Ü noch %...
Aber nachdem ich die Datei zunächst selbst erzeugt habe und als UTF-8-Format gespeichert habe, kann ich sie exakt so beschreiben, wie ich das vor hatte. Nun muss ich nur schauen, dass der ByteBuffer auch groß genug bleibt, um längere Passagen Text zu schlucken.

Könnt den Thread gern als gelöst markieren oder wie auch immer geartet (schließen).
 

Ähnliche Java Themen

Neue Themen


Oben