2010-09-11 4 views
2

J'ai ce type de structure que je veux à la fois lire et écrire dans un fichier, et je veux le faire le plus rapidement possible.Java Binary IO Écrire et lire

class Map 
{ 
    String name; 
    int tiles[][]; 
} 

Quelle est la meilleure façon de procéder? Je suis principalement un programmeur C++ et je ne connais pas la meilleure façon de le faire en Java. Il semble que ce devrait être très simple, mais je ne sais pas comment faire binaire io en Java.

C'est ce que j'ai créé à ce jour:

void Write(String fileName) 
{ 
    final ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName))); 

    oos.writeUTF(name); 
    oos.writeInt(tiles.length); 
    oos.writeInt(tiles[0].length); 
    for(int i = 0; i < tiles.length; i++) 
    for(int j = 0; j < tiles[0].length; j++) 
     oos.writeInt(tiles[i][j]); 

    oos.close(); 
} 

void Read(String fileName) 
{ 
    final ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file))); 

    name = ois.readUTF(); 

    int w = ois.readInt(); 
    int h = ois.readInt(); 

    tiles = new int[h][w]; 

    for(int i = 0; i < h; i++) 
    for(int j = 0; j < w; j++) 
     tiles[i][j] = ois.readInt(); 

    ois.close(); 
} 

Est-ce à peu près aussi vite que je peux obtenir?

+0

A pris note devrait être qu'il existe un 'utilisé java.util très commun. Carte' classe. Vous aimeriez renommer votre classe 'Map' en quelque chose de différent pour éviter les conflits de noms et les confusions d'autres développeurs (re) visualisant votre code. – BalusC

Répondre

3

http://download.oracle.com/javase/6/docs/api/java/io/ObjectOutputStream.html

// change to class to support serialization 
class Map implements Serializable 
{ 
    String name; 
    int tiles[][]; 
} 

extrait de code à écrire objet

FileOutputStream fos = new FileOutputStream("t.tmp"); 
ObjectOutputStream oos = new ObjectOutputStream(fos); 

Map m = new Map(); 

// set Map properties ... 

oos.writeObject(m); 
oos.close(); 
+1

'Map' devrait être mis en œuvre' Serializable'. Et donnez un lien vers une version plus récente des documents. – Bozho

+0

la classe Map nécessite d'implémenter l'interface Serializable pour que cela fonctionne –

3

Si tout ce que vous voulez faire est d'écrire qu'une seule et seule structure, vous devez remettre le code sérialisation et désérialisation. Je vous recommande d'écrire un nombre, puis les caractères de chaîne, puis les dimensions du tableau, puis tous les entiers. Vous devrez vous soucier de l'ordre des octets pour vous-même, en prenant deux octets pour chaque caractère et quatre pour chaque int.

Ne pas utiliser Java sérialisation si vous avez besoin de vitesse, et ne pas utiliser NIO juste pour un fichier de disque monothread la situation E/S. Utilisez un flux tamponné. Etes-vous sûr qu'il s'agit réellement d'une opération critique en termes de performances? Quelle est la taille de ce tableau, de toute façon?

Avez-vous considéré la capacité de mappage de mémoire de NIO? Maintenant vous faites le gros du travail. Faire de nombreux petits fichiers va probablement vous donner des brûlures d'estomac dans tous les cas. Notez que je distingue deux choses que vous pouvez faire avec NIO: vous pouvez utiliser les canaux et les tampons pour lire et écrire. Je suis assez douteux de l'avantage de la performance de lire simplement dans une limace de données d'un fichier. Vous pouvez également créer des mappages de mémoire et laisser le noyau entrer et sortir les données. pourrait bien fonctionner pour vous, en fonction du volume total de données et de la configuration de la mémoire impliquée.

+0

La lecture des fichiers sera critique dans le temps. Chaque fichier fera partie de la carte totale. Donc, chaque carte peut avoir une taille de 30x30 à 50x50, mais quand un personnage se déplace, je vais devoir les lire à la volée. –

+0

@gamernb Peut-être que vous devriez demander si votre approche générale est bonne ou non. :) Vous pouvez stocker beaucoup 30x30 ou 50x50 en mémoire ou en cache. – InsertNickHere

1

J'ai une technique très spécifique que j'utilise pour ce genre de chose. C'est en quelque sorte une approche hybride que je trouve aboutit au code io de base le plus performant, tout en maintenant la lisibilité et la compatibilité avec la sérialisation Java.

La réflexion utilisé dans la sérialisation Java a été la partie qui a été pensé historiquement à être lent, et il était lent. Mais depuis l'ajout de sun.misc.Unsafe, cette partie est en réalité incroyablement rapide. Il y a toujours le hit initial du tout premier appel à clazz.getDeclaredFields() et d'autres méthodes de type 'getDeclared' de java.lang.Class, mais ceux-ci sont mis en cache au niveau de la VM, ils sont donc peu coûteux après le premier (très perceptible) frappé.

Les frais généraux restant de sérialisation Java est l'écriture de données de descripteur de classe; le nom de la classe, les champs et les types, etc.Si les objets java étaient en XML, ce serait comme écrire d'abord le xsd pour que la structure soit connue, puis écrire les données xml sans les balises. Il est en fait très performant dans certaines situations, par exemple si vous avez besoin d'écrire plus de 100 instances du même type de classe dans le même flux - vous ne sentirez jamais l'impact des données des descripteurs de classes en même temps. début du flux. Mais si vous avez juste besoin d'écrire une instance de cette classe et peut-être pas grand-chose d'autre, il existe un moyen d'inverser les choses à votre avantage. Au lieu de transmettre votre objet au flux, ce qui entraîne la première écriture du descripteur de classe suivi des données réelles, passez le flux à l'objet et passez directement à la partie d'écriture des données. Bottom line est que vous prenez la responsabilité de la partie de la structure dans votre code plutôt que d'avoir le ObjectOutput/ObjectInput le faire. Remarque, j'ai également renommé votre classe de Map à TileMap. Comme le souligne BalusC, ce n'est pas un bon nom de classe.

import java.io.*; 

public class TileMap implements Externalizable { 

    private String name; 
    private int[][] tiles; 

    public TileMap(String name, int[][] tiles) { 
     this.name = name; 
     this.tiles = tiles; 
    } 

    // no-arg constructor required for Externalization 
    public TileMap() { 
    } 

    public void writeExternal(ObjectOutput out) throws IOException { 
     out.writeUTF(name); 
     out.writeInt(tiles.length); 
     for (int x = 0; x < tiles.length; x++) { 
      out.writeInt(tiles[x].length); 
      for (int y = 0; y < tiles[x].length; y++) { 
       out.writeInt(tiles[x][y]); 
      } 
     } 
    } 

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 
     this.name = in.readUTF(); 
     this.tiles = new int[in.readInt()][]; 
     for (int x = 0; x < tiles.length; x++) { 
      tiles[x] = new int[in.readInt()]; 
      for (int y = 0; y < tiles[x].length; y++) { 
       tiles[x][y] = in.readInt(); 
      } 
     } 
    } 

} 

Une écriture ressemblerait à ceci:

public static void write(TileMap tileMap, OutputStream out) throws IOException { 
    // creating an ObjectOutputStream costs exactly 4 bytes of overhead... nothing really 
    final ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(out)); 

    // Instead of oos.writeObject(titleMap1) we do this... 
    tileMap.writeExternal(oos); 

    oos.close(); 
} 

Et une lecture ressemblerait à ceci:

public static TileMap read(InputStream in) throws IOException, ClassNotFoundException { 
    final ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(in)); 

    // instantiate TileMap yourself 
    TileMap tileMap = new TileMap(); 

    // again, directly call the readExternal method 
    tileMap.readExternal(ois); 

    return tileMap; 
}