2011-01-27 2 views
3

Comment remplacer la méthode removeEldestEntry pour enregistrer l'entrée la plus ancienne dans le fichier? Aussi comment limiter la taille d'un fichier comme je l'ai fait dans LinkedHashMap. Voici le code:removeEldestEntry overriding

import java.util.*; 

public class level1 { 
private static final int max_cache = 50; 
private Map cache = new LinkedHashMap(max_cache, .75F, true) { 
protected boolean removeEldestEntry(Map.Entry eldest) { 
    return size() > max_cache; 
} 
}; 


public level1() { 
for (int i = 1; i < 52; i++) { 
    String string = String.valueOf(i); 
    cache.put(string, string); 
    System.out.println("\rCache size = " + cache.size() + 
         "\tRecent value = " + i + " \tLast value = " + 
         cache.get(string) + "\tValues in cache=" + 
         cache.values()); 

} 

J'ai essayé d'utiliser FileOutputStream:

private Map cache = new LinkedHashMap(max_cache, .75F, true) { 
    protected boolean removeEldestEntry(Map.Entry eldest) throws IOException { 
     boolean removed = super.removeEldestEntry(eldest); 
     if (removed) { 
      FileOutputStream fos = new FileOutputStream("t.tmp"); 
      ObjectOutputStream oos = new ObjectOutputStream(fos); 

      oos.writeObject(eldest.getValue()); 

      oos.close(); 
     } 
     return removed; 
    } 

Mais j'ai gagné une erreur

erreur (15,27): removeEldestEntry (java.util.Map .Entry) in ne peut pas remplacer removeEldestEntry (java.util.Map.Entry) dans java.util.LinkedHashMap; méthode surchargée ne jette pas java.io.IOException

Sans le compilateur IOExecptio demande de gérer IOexception et Filenotfoundexception. Peut-être existe-t-il un autre moyen? SVP montrez-moi un exemple de code, je suis nouveau en Java et j'essaie juste de comprendre les principes de base de la mise en cache à 2 niveaux. Thx

+0

BTW super.removeEldestEntry (aîné) retourne toujours faux. Vous devez le remplacer pour renvoyer true lorsque vous souhaitez supprimer l'entrée la plus ancienne. Votre fichier t.tmp ne contient que la dernière entrée supprimée. Est-ce ce que vous vouliez? –

Répondre

3

Vous devez d'abord vous assurer que votre méthode remplace correctement le parent. Vous pouvez apporter de légères modifications à la signature, par exemple en lançant uniquement une exception vérifiée plus spécifique qui est une sous-classe d'une exception vérifiée déclarée dans le parent. Dans ce cas, le parent ne déclare aucune exception vérifiée, donc vous ne pouvez pas l'affiner davantage et ne pouvez pas lancer d'exceptions vérifiées. Donc, vous devrez gérer le IOException localement. Il y a plusieurs façons de le faire, convertissez-le en RuntimeException et/ou enregistrez-le.

Si vous êtes préoccupé par la taille du fichier, vous ne voulez probablement pas conserver uniquement la dernière entrée supprimée, mais beaucoup d'entre eux - vous devriez donc ouvrir le fichier pour ajouter.

Vous devez retourner true de la méthode pour supprimer réellement l'aîné et vous devez décider si l'élément doit être retiré. Lorsque vous travaillez avec des fichiers, essayez try/finally pour vous assurer que vous fermez la ressource même s'il y a une exception. Cela peut devenir un peu moche - parfois c'est sympa d'avoir une méthode utilitaire pour faire la clôture, donc vous n'avez pas besoin d'essayer/attraper.

En règle générale, vous devez également utiliser un tampon pour les E/S de fichier, ce qui améliore considérablement les performances. Dans ce cas, utilisez le flux de fichier dans un java.io.BufferedOutputStream et indiquez-le au ObjectOutputStream.

Voici quelque chose qui peut faire ce que vous voulez:

private static final int MAX_ENTRIES_ALLOWED = 100; 
private static final long MAX_FILE_SIZE = 1L * 1024 * 1024; // 1 MB 

protected boolean removeEldestEntry(Map.Entry eldest) { 
    if (size() <= MAX_ENTRIES_ALLOWED) { 
     return false; 
    } 

    File objFile = new File("t.tmp"); 
    if (objFile.length() > MAX_FILE_SIZE) { 
     // Do something here to manage the file size, such as renaming the file 
     // You won't be able to easily remove an object from the file without a more 
     // advanced file structure since you are writing arbitrary sized serialized 
     // objects. You would need to do some kind of tagging of each entry or include 
     // a record length before each one. Then you would have to scan and rebuild 
     // a new file. You cannot easily just delete bytes earlier in the file without 
     // even more advanced structures (like having an index, fixed size records and 
     // free space lists, or even a database). 
    } 

    FileOutputStream fos = null; 
    try { 
     fos = new FileOutputStream(objFile, true); // Open for append 
     ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 

     oos.writeObject(eldest.getValue()); 
     oos.close(); // Close the object stream to flush remaining generated data (if any). 
     return true; 
    } catch (IOException e) { 
     // Log error here or.... 
     throw new RuntimeException(e.getMessage(), e); // Convert to RuntimeException 
    } finally { 
     if (fos != null) { 
      try { 
       fos.close(); 
      } catch (IOException e2) { 
       // Log failure - no need to throw though 
      } 
     } 
    } 
} 
+1

C'est ce dont j'ai besoin! Merci beaucoup! – BraginiNI

1

Vous ne pouvez pas modifier la signature de méthode lors du remplacement d'une méthode. Vous devez donc gérer l'exception dans la méthode substituée au lieu de la lancer.

Il contient une bonne explication sur la façon d'utiliser try et catch: http://download.oracle.com/javase/tutorial/essential/exceptions/try.html

+0

+1 Exactement. Votre nouvelle méthode doit être un remplacement de l'existant en termes de signature, ce qui signifie que, du point de vue externe, il ne doit pas lancer d'exceptions (vérifiées). Cela peut souvent être un peu douloureux, et je ne pense pas qu'il existe une approche générale complètement satisfaisante pour surmonter cela. –