2010-10-19 20 views
0

J'ai un périphérique embarqué qui exécute des applications Java qui peuvent entre autres servir des pages web XHTML (je pourrais écrire les pages comme autre chose que XHTML, mais je ' m visant pour cela pour le moment).Échapper un grand nombre de caractères pour affichage sur la page Web XHTML via Java

Lorsqu'une demande de page Web traitée par mon application est reçue, une méthode est appelée dans mon code avec toutes les informations sur la requête, y compris un flux de sortie pour afficher la page.

Sur l'une de mes pages, je souhaite afficher un fichier (journal) pouvant atteindre 1 Mo.

Je peux afficher ce fichier en utilisant le code sans échappement suivant:

final PrintWriter writer; // Is initialized to a PrintWriter writing to the output stream. 
final FileInputStream fis = new FileInputStream(file); 
final InputStreamReader inputStreamReader = new InputStreamReader(fis); 
try { 
    writer.println("<div id=\"log\" style=\"white-space: pre-wrap; word-wrap: break-word\">"); 
    writer.println(" <pre>"); 
    int length; 
    char[] buffer = new char[1024]; 
    while ((length = inputStreamReader.read(buffer)) != -1) { 
     writer.write(buffer, 0, length); 
    } 
    writer.println(" </pre>"); 
    writer.println("</div>"); 
} finally { 
    if (inputStreamReader != null) { 
     inputStreamReader.close(); 
    } 
} 

Cela fonctionne assez bien, et affiche le fichier entier dans une seconde ou deux (un délai acceptable).

Ce fichier peut (et en pratique, contient) contenir des caractères non valides XHTML, le plus souvent <>. J'ai donc besoin de trouver un moyen d'échapper à ces personnages.

La première chose que j'ai essayé était une section CDATA, mais comme documenté here ils ne s'affichent pas correctement dans IE8.

La deuxième chose que j'ai essayé était une méthode comme ce qui suit:

// Based on code: https://stackoverflow.com/questions/439298/best-way-to-encode-text-data-for-xml-in-java/440296#440296 
// Modified to write directly to the stream to avoid creating extra objects. 
private static void writeXmlEscaped(PrintWriter writer, char[] buffer, int offset, int length) { 
    for (int i = offset; i < length; i++) { 
     char ch = buffer[i]; 

     boolean controlCharacter = ch < 32; 
     boolean unicodeButNotAscii = ch > 126; 
     boolean characterWithSpecialMeaningInXML = ch == '<' || ch == '&' || ch == '>'; 

     if (characterWithSpecialMeaningInXML || unicodeButNotAscii || controlCharacter) { 
      writer.write("&#" + (int) ch + ";"); 
     } else { 
      writer.write(ch); 
     } 
    } 
} 

Ce échappe correctement les personnages (j'allais l'étendre pour échapper à des caractères non valides HTML si nécessaire), mais la page Web prend alors Plus de 15 secondes pour afficher et d'autres ressources sur la page (images, feuille de style css) échouent par intermittence à charger (je crois en raison des demandes de leur expiration parce que le processeur est ancré).

J'ai essayé d'utiliser un BufferedWriter devant la PrintWriter ainsi que de changer la taille de la mémoire tampon (à la fois pour la lecture du fichier et pour le BufferedWriter) de diverses manières, sans amélioration.

Existe-t-il un moyen d'échapper tous les caractères invalides XHTML qui ne nécessitent pas d'itérer sur chaque caractère dans le flux? A défaut, est-il possible d'accélérer suffisamment mon code pour afficher ces fichiers en quelques secondes?

Je vais envisager de réduire la taille des fichiers journaux si je le devais, mais j'espérais les faire au moins 250-500 Ko de taille (avec 1 Mo étant idéal).

J'ai déjà une méthode pour télécharger simplement les fichiers journaux, mais je voudrais les afficher dans le navigateur aussi bien pour le dépannage simple/lecture. Si il y a un moyen de définir les en-têtes pour qu'IE8/Firefox affiche simplement le fichier dans le navigateur sous la forme d'un fichier texte, je considérerais cela comme une alternative (et avoir une page entière dédiée au fichier sans XHTML de gentil).


EDIT:

Après avoir fait le test change suggéré par Cameron Skinner et de la performance, il ressemble à l'écriture échappé prend environ 1.5-2x aussi longtemps que la version écrite bloc. Ce n'est pas rien, mais je ne vais probablement pas être en mesure d'obtenir une énorme accélération en jouant avec.

Je dois juste réduire la taille maximale du fichier journal.

Répondre

1

Un petit changement qui (bien, pourrait) augmenter de manière significative la vitesse est de changer

writer.write("&#" + (int) ch + ";"); 

à

writer.write("&#"); 
writer.write((int)ch); 
writer.write(";"); 

concaténation de chaîne est extrêmement coûteux que Java alloue un nouveau tampon de chaîne temporaire chaque opérateur +, vous générez deux tampons temporaires chaque fois qu'il y a un caractère à remplacer.

EDIT: Un des commentaires sur une autre réponse est très pertinent: trouvez où le bit lent est le premier. Je suggère de tester les journaux qui n'ont pas de caractères à échapper et de nombreux caractères à échapper.

Je pense que vous devriez faire le changement suggéré de toute façon, car cela ne vous coûte que quelques secondes de votre temps.

+0

Merci pour la suggestion. Je l'accepte comme basé sur les tests de performance, il semble que je ne suis pas susceptible d'être en mesure d'augmenter la vitesse beaucoup plus. –

1

Vous pouvez essayer StringEscapeUtils de commons-lang:

StringEscapeUtils.escapeHtml(writer, string); 
+0

Cela risque-t-il d'être plus rapide que de les boucler et de les remplacer moi-même? Gardez à l'esprit que cela nécessite de convertir le 'char []' que j'ai dans une chaîne en premier. Je préférerais éviter les dépendances car elles devraient être regroupées directement dans mon pot (gardez à l'esprit que c'est un périphérique embarqué). –

+1

Vous devez d'abord mesurer * où * votre programme est lent. Il peut s'agir soit du traitement des caractères, soit des appels répétés à 'write '. Essayez les choses suivantes: • écrivez 10000 fois 100 octets. • écrire 100 fois 10000 octets. • écrire 1000000 fois 1 octet. –

+0

Données de performance ajoutées à la question. –

1

Une option est pour vous de servir le contenu du journal à l'intérieur d'un iframe hébergé à l'intérieur de votre page Web. La source de iframe peut pointer vers une URL qui sert le contenu en tant que texte.