12. november 2004 - 18:31Der er
23 kommentarer og 1 løsning
Header-information gemt i XML-fil
Jeg har en applikation, hvor jeg læser fra en binær fil, jf.
import java.io.*;
public class Laesfil {
public static void main(String[] args) throws IOException { File f=new File("f:/Java/Projects/Diverse/fil.dat"); DataInputStream is = new DataInputStream(new FileInputStream(f)); int i; double d; String s; i=is.readInt(); d=is.readDouble(); b=is.readByte(); s=is.readUTF(); is.close(); }
}
Jeg kunne godt tænke mig at gemme header-informationen, dvs. information om felternes navne og type i en XML-fil og derefter bruge denne XML-fil til at styre indlæsningen.
Er der en, der kan angive et simpelt eksempel på dette?
public class XmlBinFilCtrl { public static final int FIELD_BYTE = 1; public static final int FIELD_SHORT = 2; public static final int FIELD_INT = 3; public static final int FIELD_LONG = 4; public static final int FIELD_FLOAT = 5; public static final int FIELD_DOUBLE = 6; public static int parseType(String s) { if(s.equals("byte")) return FIELD_BYTE; if(s.equals("short")) return FIELD_SHORT; if(s.equals("int")) return FIELD_INT; if(s.equals("long")) return FIELD_LONG; if(s.equals("float")) return FIELD_FLOAT; if(s.equals("double")) return FIELD_DOUBLE; return -1; } public static Field[] readConfig(String xmlctrl) throws SAXException, IOException, ParserConfigurationException { DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(new File(xmlctrl)); NodeList elements = doc.getElementsByTagName("field"); Field[] res = new Field[elements.getLength()]; int[] types = new int[elements.getLength()]; for (int i = 0; i < elements.getLength(); i++) { res[i] = new Field(); res[i].setName(elements.item(i).getAttributes().getNamedItem("name").getNodeValue()); res[i].setType(parseType(elements.item(i).getAttributes().getNamedItem("type").getNodeValue())); } return res; } public static Map readData(DataInputStream dis, Field[] fields) throws IOException { Map res = new HashMap(); for(int i = 0; i < fields.length; i++) { String name = fields[i].getName(); switch(fields[i].getType()) { case FIELD_BYTE: res.put(name, new Byte(dis.readByte())); break; case FIELD_SHORT: res.put(name, new Short(dis.readShort())); break; case FIELD_INT: res.put(name, new Integer(dis.readInt())); break; case FIELD_LONG: res.put(name, new Long(dis.readLong())); break; case FIELD_FLOAT: res.put(name, new Float(dis.readFloat())); break; case FIELD_DOUBLE: res.put(name, new Double(dis.readDouble())); break; } } return res; } public static void writeData(Map data, DataOutputStream dos, Field[] fields) throws IOException { for(int i = 0; i < fields.length; i++) { String name = fields[i].getName(); switch(fields[i].getType()) { case FIELD_BYTE: dos.writeByte(((Byte)data.get(name)).byteValue()); break; case FIELD_SHORT: dos.writeShort(((Short)data.get(name)).shortValue()); break; case FIELD_INT: dos.writeInt(((Integer)data.get(name)).intValue()); break; case FIELD_LONG: dos.writeLong(((Long)data.get(name)).longValue()); break; case FIELD_FLOAT: dos.writeFloat(((Float)data.get(name)).floatValue()); break; case FIELD_DOUBLE: dos.writeDouble(((Double)data.get(name)).doubleValue()); break; } } } public static void main(String[] args) throws Exception { Field[] f = readConfig("C:\\ctrl.xml"); DataOutputStream dos = new DataOutputStream(new FileOutputStream("C:\\bin.dat")); Map hm1 = new HashMap(); hm1.put("a", new Integer(123)); hm1.put("b", new Double(123.456)); writeData(hm1, dos, f); Map hm2 = new HashMap(); hm2.put("a", new Integer(321)); hm2.put("b", new Double(654.321)); writeData(hm2, dos, f); dos.close(); DataInputStream dis = new DataInputStream(new FileInputStream("C:\\bin.dat")); Map hm3 = readData(dis, f); System.out.println(hm3); Map hm4 = readData(dis, f); System.out.println(hm4); dis.close(); } }
class Field { private String name; private int type; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getType() { return type; } public void setType(int type) { this.type = type; } }
Jeg kender intet til XML men har læst dine artikler. Bør man i dette tilfælde bruge SAX eller W3C DOM? I mit tilfælde har man nok ikke som sådan brug for at kunne spole frem og tilbage, idet jeg læser header'en ind og ikke andet.
->arne_v: Et enkelt tillægsspm.: Når der er læst ind igen fra filen og gemt i hm3 og hm4, hvordan opretter jeg så (dynamisk) på baggrund heraf f.eks. relevante arrays: int[] a=new int[100]; double[] b=new double[100]; osv. - som jeg kan arbejde videre på?
->arne_v: Ville det i virkeligheden være nemmere at gemme header-informationen i et objekt, som derefter serialiseres/deserialiseres vha. (ObjectOutputStream og ObjectInputStream) i stedet for at anvende XML?
Jo - det var derfor jeg valgte en map hvor man ikke behøver kende navnene på forhånd.
re 13:40>
Sagtens hvis informationen kun skal læses/skrive af programmet. Men hvis man gerne vil kunne læse beskrivelse og måske endda rette i den med en editor, så er XML godt.
->arne_v re 13:10> Men hvordan får jeg oprettet variabler svarende til indeholdet af Map'en/headeren? Kan jeg overhovedet gøre dette på run-time på en nem måde??
Jeg forestiller mig, at jeg ved brug af header-informationen indlæser en "record" fra en data-fil, hvor indholdet puttes i variabler som angivet i headeren, idet jeg derved kan arbejde videre på disse variabler i min Java-kode.
->arne_v: Hvordan ville du i det konkrete tilfælde oprette variablene a og b ud fra Map'en (altså uden at kende navnene a og b på forhånd)? Det er vel ikke ligetil (?)
->arne_v: Jeg forestiller mig noget i lighed med et database-opslag, hvor man indlæser (alle) felter fra en tabel, og hvor man så kan arbejde videre på de indlæste variable. I dette tilfælde er variablernes navne (og typer) gemt i en header, som styrer indlæsningen. I "halen" på indlæsningen vil jeg så gerne kunne arbejde videre på de indlæste variable og måske skrive tilbage i en ny fil. Jeg er derfor nødt til at sikre mig, variablerne oprettes i koden som angivet i headeren.
->arne_v: Jeg tror jeg forstår, hvor du vil hen. Når du er færdig med indlæsningen, har du en HashMap, hvor nøgleværdierne er navnene på variablerne og indholdet er værdierne med de rigtige typer.
Men hvis man skal arbejde videre med indholdet, udestår det stadig at overføre indholdet til primitive (array-)typer med de rigtige navne, f.eks. svarende til: ArrayList xa=(ArrayList)hm2.get("a"); ArrayList xb=(ArrayList)hm2.get("b"); int dim=xa.size(); int[] a=new int[dim]; double[] b=new double[dim]; for (int i=0;i<dim;i++) { a[i]=((Integer)xa.get(i)).intValue(); b[i]=((Double)xb.get(i)).doubleValue(); System.out.println(a[i]); System.out.println(b[i]); }
Nu kan man så arbejde videre på a[] og b[] som primitive (array-)typer.
Men, men..jeg kan jo kun udstede erklæringerne int[] a=new int[dim]; double[] b=new double[dim]; når jeg kender typerne af a og b, og det gør jeg først på runtime! Jeg kan med andre ord ikke udstede erklæringerne vedr. a og b dynamisk ud fra header-oplysningerne, idet de ikke er kendt på compile-time.
->arne_v: Ok. Jeg takker for stor vedholdenhed og tålmodighed vedr. dette spm.!
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.