PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Java - HTML streamen und in Datei schreiben


NickDiamond
2007-05-11, 16:15:27
Hallo,
ich möchte den Quelltext von Internetseiten, also einfach nur den HTML-Code, automatisch in einer (Text-)Datei abspeichern lassen.

Wie ich das ganze einfach auf der Standard-Ausgabe ausgebe hab ich schon. Siehe meinen Quelltext:


...
public static void main(String[] args) throws IOException {


URL myURL = new URL(text);

BufferedReader in = new BufferedReader(new InputStreamReader(myURL.openStream()));

String line;
while ( (line = in.readLine()) != null) {

InFile (filename, line);
System.out.println(line);
}





public static void InFile (String filename, String text){

FileOutputStream schreibeStrom =
new FileOutputStream(filename);
for (int i=0; i < text.length(); i++){
schreibeStrom.write((byte)text.charAt(i));
}

schreibeStrom.close();
}
}


Hab jetzt nur die entscheidenden Bruchstücke aufgelistet. Also die Variablen sind "gefüllt" ;) !

In der main-Methode wird der Stream Zeilenweise ausgegeben. Mit der Konsolen-Ausgabe funktioniert das natürlich.
Allerdings wird mit diesem Code nur die letzte Zeile des HMTL-Codes in die Datei geschrieben.
Ist natürlich logisch wegen "in.readLine()" , nur weiss ich nicht wie ich es abändern muss, so dass nachher der komplette HTML-Code in der Datei steht.

Kann jemand helfen ?

edit:
wei ich mit FileWriter einen String in eine Datei schreibe ist mir auch klar, nur weiss ich nicht wie ich das hier auf diesen Stream anwenden kann !!??!!

UliBär
2007-05-11, 16:44:40
Du solltest den Konstruktor für FileOutputStream verwenden:

public FileOutputStream(File file, boolean append) throws FileNotFoundException

;)

NickDiamond
2007-05-11, 18:30:34
wow, danke.
das hat schon mal funktioniert.
Nur wird die erste Zeile nicht in die Datei übergeben.
In der Konsolenausgabe übrigens auch. Fällt mir jetzt erst auf.

Woran liegt das ?

P.S.:
die Frage wie ich den ganzen Stream noch richtig parse, stelle ich später

NickDiamond
2007-06-03, 20:50:07
So,
sitze mal wieder vor einem Problem.
Ich beschreibe mal die Situation:
Eine Text-Datei liegt vor (eine bereits weitgehends bereinigte HTML-Datei), der Inhall soll in ein neues Dateiformat geändert werden (welches genau ist erstmal nicht wichtig). Nun gibt es je nach vorhandener Datei konstante Werte (also Text/Strings) , und welche die sich ändern (können).
Wie kann ich nun bestimmte (veränderliche) Textstellen als Variablen (also String xy) übernehmen, sodass ich diese wiederverwenden kann ??
Das Programm soll "universell" einsetzbar sein, und nicht nur auf einen (ganz genau) festlgelegten Text.

hoffe das Problem ist verständlich. Hänge da jetzt irgendwie schon länger, und hab nicht wirklich eine Lösung gefunden.
Kann jemand helfen ?

Danke vorab ;)

edit:
ich habe irgendwie dass Problem, dass ich nicht weiss wie dass Programm erkennen kann wann genau ein betimmtes Wort auftaucht.
selbst sowas wie
if ( line.matches("xy") ) ... bla bla bringt mich nicht weiter. Irgendwie fehlt mir eine passende Funktion dieser Streams (FileReader)...

Hamud
2007-06-03, 21:26:09
Mit dem String#replace methode bist du sehr mächtig. Schreib doch deinen Output in einen ByteArrayOutputStream. lass dir Die Ausage als String geben. dann kannst du mit replace Änderungen vornehmen und am Ende Schreibst du deinen String in die Datei.

Übrigens würde ich zum Streamen normalerweise keinen Reader nehmen. Ist totaler Overkill, weil du da beim Lesen und Schreiben eine Zeichensatzkodierung machen musst (passiert Automatisch).

Leider habe ich gerade keine Entwicklungsumgebung aber metamäßig:

Url a = new URL("bla");
InputStream in = new BufferedInputStream(myURL.openStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
int i = -1;
byte[] tmp = new byte[1024];
while((i = in.read(tmp)!=-1))
{
out.write(tmp,0,i);
}
in .close();
out.close();
String http_page = out.toString();
http_page = http_page.replaceAll(.....);
FileOutputStream outStream =
new FileOutputStream(filename);
outStream.write(http_page.getBytes());
outStream.close();


Da wo der replaceAll steht kannst du aus einem Konfigfile die Ersetzungen Laden und Anwenden.
Für Forgeschrittene: nach dem Replacements kann man prüfen, ob sich was geändert hat, und dann die erstzung nochmal machen, Damit kann man rekursive Ersetzungen ganz leicht machen. Nur dann muss mit der Definition etwas Vorsichtiger Sein, um sich keine Endlosschleife zu Programmieren.

NickDiamond
2007-06-03, 21:53:40
Danke schon mal für die super schnelle Antwort :smile:

Ich wusste nicht dass das Einlesen der URL als Reader automatisch eine Codierung ausführt, danke für die Erklärung.
Werde das dann wohl noch ändern, obwohl das bisherige Einlesen der URL, sprich des HTML-Codes und dessen Bereinigung bisher problemlos funktioniert.

Aber dass Auslesen einer Datei sollte ja im Prinzip nichts anderes sein als ein Internet-Stream.
Und ich glaube mit der angesprochenen replace-methode dürfte ich weiterkommen :wink:
(wobei ich die zum bereinigen schon verwende)

Bin mir eh grad diverse Seiten mit möglichen String-Operationen am durchlesen, aber eine Erklärung am direkten Beispiel ist immer am besten.

Zum Verständnis:
Wie werden hier die Zeichen eingelesen ? Zeichenweise ? Zeilenweise ?
Wie genau kann ich mit replaceAll z.B. Namen extrahieren, um sie an anderen Stellen nochmal anwenden zu können (ohne vorher zu wissen welche Namen zu finden sind, also man weiss nur dass was vor und nach dem Namen steht)?

Bin echt begeistert wie schnell hier geholfen wird, so wird es dann letztendlich vielleicht doch noch ein produktiver Sonntag :rolleyes:

Hamud
2007-06-09, 09:52:19
Ich wusste nicht dass das Einlesen der URL als Reader automatisch eine Codierung ausführt, danke für die Erklärung.
Werde das dann wohl noch ändern, obwohl das bisherige Einlesen der URL, sprich des HTML-Codes und dessen Bereinigung bisher problemlos funktioniert.
Solange man keine Probleme mit der Kodierung hat, merkt man das auch nicht; Außerdem kann es einen gewissen Performanceunterschied machen.


Aber dass Auslesen einer Datei sollte ja im Prinzip nichts anderes sein als ein Internet-Stream.

Ist es auch nicht. Und das ist gerade das geniale dadran.



Zum Verständnis:
Wie werden hier die Zeichen eingelesen ? Zeichenweise ? Zeilenweise ?


Streams werden erstmal immer Zeichenweise eingelesen, wenn du aber eine Reader dazwischenklemmst, sucht der nach dem Zeilenumbruch. Der geht dir dann im Orginalen auch verloren. Es ist also egal ob vorher eine UXIX oder DOS kodierung vorglegen hat. Du musst dich beim rausschreiben, selbst dadrum kümmern.


Wie genau kann ich mit replaceAll z.B. Namen extrahieren, um sie an anderen Stellen nochmal anwenden zu können (ohne vorher zu wissen welche Namen zu finden sind, also man weiss nur dass was vor und nach dem Namen steht)?


Schaud dir mal die Klasse Pattern und Matcher an, gerade im zusammenspiel mit Matchinggroups. z.B. test123bla mit regex test(.*)bla und matchinggroup 1 liefert 123.

NickDiamond
2007-06-09, 21:46:35
Ich danke dir erstmal für deine Erklärungen :smile:

Schaud dir mal die Klasse Pattern und Matcher an, gerade im zusammenspiel mit Matchinggroups. z.B. test123bla mit regex test(.*)bla und matchinggroup 1 liefert 123.

pattern und matches hab ich mir schon mal angeschaut. Scheint ziemlich mächtig zu sein, allerdings wurde mir nicht alles sofort schlüssig (leider hab ich auch in meinem Java-Buch nichts darüber gefunden).

Hab das extrahieren (der variablen Namen) aus dem HTML-Code aber auch ohne pattern und matches hinbekommen.

Diese habe ich dann in einem (string-)Array abgelegt, so dass man jederzeit wieder darauf zurückgreifen kann. Nur habe ich das Problem dass ich vorher nicht weiss wie viele Namen ich abspeichern muss.
Lösen könnte ich dies, in dem ich die Häufigkeit des Vorkommens eines einzelnen bestimmten Wortes zählen würde (dieses Wort steht immer automatisch hinter jedem Namen).
Dafür habe ich bis jetzt nur eine Lösung über "StreamTokenizer" gesehen.
Gibts einfachere/kürzere Lösungen ?

Oder gibt es eine ganz andere Lösung um nicht mit in der Grösse festgelegten Feldern arbeiten zu müssen ?
(Ein Feld dass man in jedem Schleifendurchlauf um eins vergrössert wäre klasse)

gruss ND

P.S.:
hätte nie gedacht das ich das mal sagen würde, aber so langsam fängt mir Java an Spass zu machen :cool:

Hamud
2007-06-10, 10:46:43
Java ist ja mittlerweile auch ziemlich mächtig und Genial.

Schau mal das Collectionframework an. Mit der Klasse ArrayList(oder alles was von List) kanns du beliebig lange(dynamische) Strukturen bauen. Mit Set(hascode und equals(ist nicht immer so trivial wies aussieht; gerade wenn man Vererbung einsetzt) müssen Implementiert sein) sorrgst du dafür, dass ein Objekt nur einemal vorkommt(Bei Sortedset sogar sortiert(Comparable Interface)), Und mit einer Map kann man zu einem Schlüssel einen Wert hinterlegen(Object beliebigen types; kann selbst wieder eine Map sein!!!)

NickDiamond
2007-06-10, 13:05:50
Wow, das mit der ArrayList klingt super.
Dazu werd ich mich dann gleich mal schlau machen :smile:

Hamud
2007-06-10, 20:01:18
Ein gutes Anfängerbuch:
http://www.galileocomputing.de/openbook/javainsel6/