Lesen von Javaobjekten von Netzwerkshares unsicher?

AlexD1979

Erfahrenes Mitglied
Hallo,
Wir haben ein Problem, dass Java Objekte, die als Datei gelesen werden, korrupt sind.
Die Dateien (Warenkörbe) liegen auf einem Netzwerkshare, von dem sich der Server die Datei holt, einliest und das Objekt parst. Nun scheint die Datei beim schreiben oder lesen nicht vollständig anzukommen und es wird kein sauberes Objekt gebaut.
Welche Möglichkeiten gibt es, dass eingelesene Objekt daraufhin zu prüfen, ob ein Fehler aufgetreten ist?
An Zeile 67 von dem Code tritt der Fehler auf und geht in den catch in Zeile 69

Code:
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

import com.j2dot.exceptions.J2InternalException;

public class ObjToFile {
	public static void saveObjectToFile(Serializable obj,String filePath) throws J2InternalException {
		FileOutputStream fos = null;
		ObjectOutputStream out = null;
		try {
			fos = new FileOutputStream(filePath);
		} catch (FileNotFoundException e) {
			J2InternalException je = new J2InternalException();
			je.initCause(e);
			throw je;
		}
		try {
			out = new ObjectOutputStream(fos);
			out.writeObject(obj);
			out.close();
		} catch (IOException e1) {
			J2InternalException je = new J2InternalException();
			je.initCause(e1);
			throw je;
		} finally {
			if (out != null)
				try {
					out.close();
				} catch (IOException e2) {
					// TODO Auto-generated catch block
					e2.printStackTrace();
				}
		}
	}
	
	public static synchronized Object loadObjectFromFile(String filePath) throws J2InternalException {
		FileInputStream fis = null;
		ObjectInputStream in = null;
		Object obj = null;
		ByteArrayInputStream bais = null;
		long fileSize = 0;
		try {
			//getting file information
			File fileToLoad = new File(filePath);
			fileSize = fileToLoad.length();
			int fileBufferSize = Long.valueOf(fileSize).intValue();
			fis = new FileInputStream(filePath);
			byte[] b = new byte[fileBufferSize];
			int readBytes = 0;
			try {
				//reading file into buffer and count read bytes
				while(readBytes < fileBufferSize){
					b[readBytes++] = (byte) fis.read();
					//readBytes++;
				}
				fis.close();
				//converting byte array to object
				bais = new ByteArrayInputStream(b);
				in = new ObjectInputStream(bais);
				obj = in.readObject();				//free memory
				bais = null;
			} catch (IOException e) {
			e.printStackTrace();
				J2InternalException je = new J2InternalException("Error loading file. Read " + readBytes + " out of " + fileBufferSize + " from file " + filePath);
				je.initCause(e);
				throw je;
			} catch (ClassNotFoundException e) {
				J2InternalException je = new J2InternalException("Error loading file. Read " + readBytes + " out of " + fileBufferSize + " from file " + filePath);
				je.initCause(e);
				throw je;
			}
		} catch (FileNotFoundException e) {
			J2InternalException je = new J2InternalException();
			je.initCause(e);
			throw je;
		} finally {
			//close all streams - if an exception occurs, streams are allready closed or lost.
			if (in != null){
				try {
					in.close();
				} catch (IOException e2) {
					e2.printStackTrace();
				}
			}
			if (bais != null){
				try {
					bais.close();
				} catch (IOException e2) {
					e2.printStackTrace();
				}
			}
			if (fis != null){
				try {
					fis.close();
				} catch (IOException e2) {
					e2.printStackTrace();
				}
			}
		}
		return obj;
	}
}

Fehlermeldung :
Code:
java.io.UTFDataFormatException
	at java.io.ObjectInputStream$BlockDataInputStream.readUTFSpan(ObjectInputStream.java:3081)
	at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3006)
	at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:2819)

und an der Stelle Zeiel 56 steht:
Code:
/**
	 * Reads span of UTF-encoded characters out of internal buffer
	 * (starting at offset pos and ending at or before offset end),
	 * consuming no more than utflen bytes.  Appends read characters to
	 * sbuf.  Returns the number of bytes consumed.
	 */
	private long readUTFSpan(StringBuilder sbuf, long utflen) 
	    throws IOException
	{
	    int cpos = 0;
	    int start = pos;
	    int avail = Math.min(end - pos, CHAR_BUF_SIZE);
	    // stop short of last char unless all of utf bytes in buffer
	    int stop = pos + ((utflen > avail) ? avail - 2 : (int) utflen);
	    boolean outOfBounds = false;

	    try {
		while (pos < stop) {
		    int b1, b2, b3;
		    b1 = buf[pos++] & 0xFF;
		    switch (b1 >> 4) {
			case 0:
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 7:	  // 1 byte format: 0xxxxxxx
			    cbuf[cpos++] = (char) b1;
			    break;

			case 12:
			case 13:  // 2 byte format: 110xxxxx 10xxxxxx
			    b2 = buf[pos++];
			    if ((b2 & 0xC0) != 0x80) {
				throw new UTFDataFormatException();
			    }
			    cbuf[cpos++] = (char) (((b1 & 0x1F) << 6) | 
						   ((b2 & 0x3F) << 0));
			    break;

			case 14:  // 3 byte format: 1110xxxx 10xxxxxx 10xxxxxx
			    b3 = buf[pos + 1];
			    b2 = buf[pos + 0];
			    pos += 2;
			    if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) {
				throw new UTFDataFormatException();
			    }
			    cbuf[cpos++] = (char) (((b1 & 0x0F) << 12) | 
						   ((b2 & 0x3F) << 6) | 
						   ((b3 & 0x3F) << 0));
			    break;

			default:  // 10xx xxxx, 1111 xxxx
			throw new UTFDataFormatException();
		    }
		}
	    } catch (ArrayIndexOutOfBoundsException ex) {
		outOfBounds = true;
	    } finally {
		if (outOfBounds || (pos - start) > utflen) {
		    /*
		     * Fix for 4450867: if a malformed utf char causes the
		     * conversion loop to scan past the expected end of the utf
		     * string, only consume the expected number of utf bytes.
		     */
		    pos = start + (int) utflen;
		    throw new UTFDataFormatException();
		}
	    }

	    sbuf.append(cbuf, 0, cpos);
	    return pos - start;
	}
 
Ohne jetzt deinen Quellcode gelesen zu haben würde ich sagen, dass dein Problem die Integrität der Daten ist. Bei diesem Problem bietet es sich immer an Hashalgorithmen zu Verwenden.
Um das umzusetzen müsstest berechnest du bevor du das Objekt serialisierst den Hash des Objekts, hängst den direkt an die gespeicherte Datei an. Wenn du dann das Objekt wieder lädst lädst du den Hash mit, berechnest wieder den Hash des Objekts. Wenn der neu berechnete Hash mit dem gespeicherten übereinstimmt ist dein Objekt richtig gespeichert/geladen worden.
Die optimale Umsetzung wäre vermutlich indem du deinen Warenkorb das Interface Externalizable implementierst. Dann kannst du beim schreiben auf den ObjectStream erst das Object schreiben lassen und direkt danach den Hash. Wie sicher dabei die Hash-Methode der Klasse Object ist weiß ich nicht.
 
Als sichere Hash-Methode sollte mindestens SHA-256 oder stärker verwendet werden da sowohl MD5 als auch SHA-1 erhebliche Mängel aufweisen. Und das nicht nur in Bezug auf Kryptographie sondern auch allgeimene Kollisionsbeständigkeit.
Aber wie Technoblade schon meinte vermute ich auch eine Intigritäts-Schwäche deiner Daten.
Auch so allgemein scheint mir der von dir beschriebene Aufbau etwas fehleranfälliger zu sein als zum Beispiel auf die lokale Platte zu schreiben.
 
Zurück