Lesen von tab-separierten Textdateien in C/C++
Durch Tabulator-Zeichen getrennte Felder in einer Textdatei
können in C/C++ recht einfach mit der Funktion fscanf()
gelesen werden. In diesem Beispiel wird eine Datei mit
Flugdaten eingelesen. Jede Zeile enthält dabei einen
Flug, der durch die Felder Routen-Nummer, Start, Ziel,
Wochentag und Uhrzeit (im Format HHMM) beschrieben.
#include <stdio.h> #define BUFLEN 255 int main(void) { char route[BUFLEN], start[BUFLEN], dest[BUFLEN]; char weekday[BUFLEN], time[BUFLEN]; FILE *flights; if ((flights = fopen("flug.tsv", "r")) == NULL) return -1; while (fscanf(flights, "%s\t%s\t%s\t%s\t%s\n", route, start, dest, weekday, time) != EOF) { printf("--- flight record ---\n"); printf("route # %s\n", route); printf("from %s to %s\n", start, dest); printf("on %s at %s\n", weekday, time); } fclose(flights); }Das Programm als Textdatei
Lesen von tab-separierten Textdateien in Java
Java (Version 1.1.8) bietet leider keinen Aufruf analog zu fscanf(). Tab-separierte
Textdateien können aber mit Hilfe der Klasse StringTokenizer
trotzem einfach eingelesen werden:
import java.io.*; import java.util.*; class ReadFlights { public static void main(String[] args) { try { BufferedReader flights = new BufferedReader(new FileReader("flug.tsv")); String line = new String(); while ((line = flights.readLine()) != null) { StringTokenizer st = new StringTokenizer(line, "\t"); System.out.println("--- flight record ---"); System.out.println("route # "+st.nextToken()); System.out.println("from "+st.nextToken()+" to "+st.nextToken()); System.out.println("on "+st.nextToken()+" at "+st.nextToken()); } } catch (IOException ioex) { System.out.println(ioex.getMessage()); ioex.printStackTrace(); } } }Das Programm als Textdatei
Lesen von tab-separierten Textdateien in Scheme
(scsh)
Benutzer der scsh (Scheme
Shell) haben es gewohnt einfach. Der infix-splitter
zerlegt eine eingelesene Textzeile in die Felder. Die scsh
ist am WSI von allen Rechnern nutzbar.
#!/bin/sh
IFS=" "
exec /afs/wsi/ppc_macx54/bin/scsh -s "$0" "$@"
!#
(let ((reader (infix-splitter (string (ascii->char 9))))
(port (open-input-file "flug.tsv")))
(let lp ((line (read-line port)))
(if (eof-object? line)
(close-input-port port)
(begin
(display (reader line))
(lp (read-line port))))))
Das Programm als TextdateiLesen von tab-separierten Textdateien in Perl
In Perl hilft die Funktion split
weiter:
#!/usr/bin/perl -w
use strict;
open FLIGHTS, "flug.tsv"
or die "Can't open: $!\n";
my $line;
while ($line = <FLIGHTS>) {
my ($route, $start, $dest, $weekday, $time) = split("\t", $line);
print "--- flight record\n";
print "route # $route\n";
print "from $start to $dest\n";
print "on $weekday at $time\n";
}
close FLIGHTS;
Das Programm als TextdateiSpeichern von Session-Daten
Session-Daten müssen permanent gespeichert werden und
beim nächsten Aufruf des CGI-Programms wieder eingelesen
werden. Die einfachste Möglichkeit besteht darin, die Daten
in einzelnen Dateien (tab-separierte Werte bieten sich auch
hier wieder an) zu sichern. Für jede Session wird eine Datei
angelegt, der Name der Datei entspricht der
Session-ID. Dieses Vorgehen hat einige Vorteile gegenüber der
Speicherung aller Session-Daten in einzigen Datei.
Buchungen organisieren
Buchungen werden am besten so gespeichert, dass alle
Buchungen eines Kunden schnell und leicht gefunden werden
können -- das ist die häufigste Operation. Deswegen wird pro
Buchung eine Datei angelegt. Da zu jedem Kunden mehrere
Buchungen gehören werden die Buchungen für diesen Kunden
wiederum in einem eigenen Verzeichnis gesammelt. Jeder Kunde
hat also sein eigenes Verzeichnis dessen Name aus dem
Kundennamen abgeleitet werden kann. Sucht man alle Buchungen
eines Kunden, guckt man nur in alle Dateien in dem
Verzeichnis dieses Kunden.
Cache-Kontrolle
Die meisten Browser speichern Seiten lokal zwischen, um so
die Zahl der Zugriffe auf den Web-Server zu minimieren. Dies
kann in Einzelfällen zu Problemen führen. Der Server hat die
Möglichkeit eine Seite so zu markieren, dass sie nicht vom
Browser gecacht wird. Hier zu sind folgende Header in der
Antwort zu setzen:
Pragma: no-cache Cache-Control: no-cacheDer Pragma-Header dient der Kompabilität zu Browsern, die HTTP 1.0 benutzen.
Den Inhalt von Verzeichnissen in C/C++ lesen
Den Inhalt eines Verzeichnis kann in C/C++ mit den
Funktionen opendir(),
readdir()
und closedir()
ausgelesen werden. Siehe Beispielcode. readdir()
liefert einen Pointer auf eine struct dirent
zurück. Die Felder dieser struct sind auf der man
page von dirent dokumentiert.
#include <sys/types.h> #include <sys/dir.h> #include <dirent.h> #include <stdlib.h> /* see man readdir and dirent */ int main(void) { DIR *dirp; struct dirent *dir_entry; /* "." means current directory */ if ((dirp = opendir(".")) == NULL) return NULL; while ((dir_entry = readdir(dirp)) != NULL) printf("There is a file %s in this directory\n", dir_entry->d_name); closedir(dirp); }Das Programm als Textdatei
Den Inhalt von Verzeichnissen in Java lesen
Die Methode
list()
der Klasse File
liefert den Inhalt des Verzeichnisses als Array von Strings
zurück.
import java.io.*; class ReadDir { public static void main(String args[]) { try { File f = new File("."); String[] entries = f.list(); for (int i = 0; i < entries.length; i++) System.out.println("There is a file " + entries[i] + "in this diretory"); } catch (Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }Das Programm als Textdatei
Den Inhalt von Verzeichnissen in Scheme lesen
Die scsh bietet zum
auslesen eines Verzeichnisses die äußerst komfortable
Funktion directory-files.
#!/bin/sh IFS=" " exec /afs/wsi/ppc_macx54/bin/scsh -s "$0" "$@" !# (for-each (lambda (name) (display (string-append "There is a file " name "in this directory")) (newline)) (directory-files "."))Das Programm als Textdatei
Den Inhalt von Verzeichnissen in Perl lesen
Perl bietet hierfür die Funktionen opendir,
readdir
und closedir.
#!/usr/bin/perl -w
use strict;
opendir DIR, "."
or die "Could not opendir: $!";
foreach my $name (readdir(DIR)) {
print "There is a files $name in this directory\n";
}
closedir DIR;
Das Programm als TextdateiURIs dekodieren (Version für C/C++)
Mit der Funktion decode_uri() können die
hex-kodieren Zeichen einer URI dekodiert werden.
#include <ctype.h> #include <string.h> #include <stdlib.h> #include <limits.h> int decode_uri(char *uri, char *resbuf) { int i = 0, j = 0; char c, code[3] = {NULL, NULL, NULL}; while ((c = uri[i++]) != NULL) { if (c == '%') if (isxdigit(uri[i]) && (uri[i+1] != NULL) && isxdigit(uri[i+1])) { strncpy(code, &uri[i], 2); resbuf[j++] = (char) strtol(code, NULL, 16); i += 2; } else return -1; else resbuf[j++] = c; } return 0; }Das Programm als Textdatei
Query-String dekodieren (Version für C/C++)
Dekodiert einen application/x-www-form-urlencoded
kodierten Query-String. Der Parameter query enthält
den Query-String, key den Schlüssel. Es wird der zum
Schlüssel key gehörige Wert zurückgegeben. Enthält der
Query-String keinen Schlüssel names key gibt
query_decode() NULL zurück.
#include <string.h> #include <stdlib.h> #define BUFLEN 255 char *query_decode(char *query, char *key) { int i; char tmp[BUFLEN], unescaped[BUFLEN], *resbuf, *pair; bzero(tmp, BUFLEN); bzero(unescaped, BUFLEN); for (i = 0; i < strlen(query); i++) tmp[i] = (query[i] == '+') ? ' ' : query[i]; if (decode_uri(tmp, unescaped) < 0) return NULL; for (pair = strtok(unescaped, "&"); pair; pair = strtok(NULL, "&")) { char *idx_key, thiskey[BUFLEN]; int vallen; idx_key = index(pair, '='); if (idx_key == NULL) return NULL; bzero(thiskey, BUFLEN); strncpy(thiskey, pair, (int)idx_key - (int)pair); vallen = strlen(pair) - ((int)idx_key - (int)pair); if (strcmp(key, thiskey) == 0) { resbuf = (char *) calloc(vallen + 1, sizeof(char)); return (resbuf == NULL) ? NULL : strncpy(resbuf, &idx_key[1], vallen); } } return NULL; }Das Programm als Textdatei
URI und Query dekodieren mit Scheme
Die Funktion decode-hex-chars dekodiert alle
hex-kodierteden Zeichen in einem
String. decode-query macht aus einem Query-String
eine Assoziationsliste.
; ,open srfi-13 srfi-14 ascii
(define (replace-plus-signs uri-string)
(string-map
(lambda (c)
(if (char=? c #\+) #\space c))
uri-string))
(define (decode-hex-chars uri-string)
(call-with-current-continuation
(lambda (esc)
(regexp-substitute/global
#f (rx (: #\% (= 2 any))) uri-string
'pre
(lambda (match)
(cond ((regexp-search (rx (: #\% (= 2 hex-digit)))
(match:substring match 0))
=> (lambda (match)
(string (hex->char (substring (match:substring match 0) 1 3)))))
(else (esc #f))))
'post))))
(define (hex->char str)
(ascii->char (string->number (string-append "#x" str))))
(define (decode-query query-string)
(map
(lambda (argval)
(string-tokenize
argval (char-set-difference char-set:full (char-set #\=))))
(string-tokenize
query-string (char-set-difference char-set:full (char-set #\&)))))
Das Programm als TextdateiURI und Query dekodieren mit Perl
Funktionen, um URI und Queryes zu dekodieren sind
Bestandteil der Perl-Bibliothek. Siehe Dokumentation des
Modules URI::Escape
und URI.
URI und Query dekodieren mit Java
Java bietet einige Klassen an, die den Umgang mit URIs
erleichtern sollen. Die Klassen URL und
URLEncode sind Bestandteil der Java Bibliothek seit
Version 1.1.8. In der Java-Bibliothek Version 1.2 ist die
Klasse URLDecode hinzugekommen. Die Klasse
URL dekodiert den Query-Teil einer URI aber
nicht. In der Java-API Version 1.4 gibt es eine unglaubliche
komplizierte Klasse namens URI, die irgendwas in
dieser Richtung macht (konnten nicht ausprobiert
werden). Spätestens hier war klar: Das ist doch alles
Mist und haben das Zeugs für das letzte Projekt eben
selber geschrieben. Wir haben für diese einfache
Aufgabe (siehe Scheme-Lösung) auch lächerliche
zwei Klassen und eine Exception gebraucht. Anmerkung der
Knowledgebase-Redaktion: An dieser Stelle folgt eine Reihe
von Kraftausdrücken, die wir gelöscht haben. Diese
Ausdrücke gehören in eine andere
Knowledgebase...
Die Klasse URI:
import java.util.*; class URI { private String resource; private Hashtable arguments; URI(String resource, Hashtable arguments) { this.resource = resource; this.arguments = arguments; } URI(String resource) { this.resource = resource; this.arguments = null; } public String getResource() { return resource; } public Hashtable getArguments() { return arguments; } public String toString() { return "Resource: '"+resource+"' Arguments: "+arguments; } }Das Programm als Textdatei (URI.java)
import java.util.*; class URIParser { private static Vector Tokenize(String s, String delim) { StringTokenizer st = new StringTokenizer(s, delim); Vector v = new Vector(); while (st.hasMoreTokens()) v.add(st.nextToken()); return v; } public URI parseResource(String s) throws URLParseException { if (s.indexOf("?") > 0) { Vector v = Tokenize(s, "?"); if (v.size() != 2) throw new URLParseException("parseResource detected a syntax error: "+s); return new URI((String) v.elementAt(0), parseArguments((String) v.elementAt(1))); } else return new URI(s); } public Hashtable parseArguments(String s) throws URLParseException { Vector args = Tokenize(s, "&"); Hashtable h = new Hashtable(); for (Enumeration e = args.elements(); e.hasMoreElements();) { String arg = (String) e.nextElement(); if (arg.indexOf("=") > 0) { Vector v = Tokenize(arg, "="); if (v.size() != 2) throw new URLParseException("parseArguments detected a syntax error: "+arg); h.put(v.elementAt(0), decodeArgument((String)v.elementAt(1))); } else h.put(arg, ""); } return h; } private String decodeArgument(String s) throws URLParseException { String t = new String(); int i,j=0; for (i = s.indexOf("%"); (i < s.length()) && (i > 0);) { if (i+3 > s.length()) throw new URLParseException("decodeArgument detected a syntax error: "+s); else { try { String code = s.substring(i,i+3).trim(); Integer intcode = new Integer(0); code = code.replace('%','#'); intcode = intcode.decode(code); t = t+s.substring(j,i)+(char)intcode.intValue(); } catch (NumberFormatException nf) { throw new URLParseException("decodeArgument detected a syntax error (number format): " +nf.getMessage()); } } j=i+3; i = s.indexOf("%", i+1); } t = t+s.substring(j,s.length()); t = t.replace('+',' '); return t; } }Das Programm als Textdatei (URIParser.java)
class URLParseException extends Exception { URLParseException(String s) { System.err.println(s); System.exit(-1); } }Das Programm als Textdatei (URLParseException.java)