Februar 19, 2021

Fun with Excel - Heute: Das liebe Komma

Excel Formeltrenner unterschied C# zur Exceloberfläche

Weiterlesen
Februar 10, 2021

"Man sieht ihnen ihren Zeilenumbruch gar nicht an."

Textdateien, Zeilenumbrüche und Betriebssysteme

Weiterlesen
Januar 26, 2021

Mit Node.js gegen den Rest der Welt

Heute: schnell mal was zippen

Weiterlesen
November 8, 2020

Mit Node.js gegen den Rest der Welt - Heute Webserver

Webserver in Node.js

Weiterlesen
Cover Image

Fun with Excel - Heute: Das liebe Komma

Excel Formeltrenner unterschied C# zur Exceloberfläche

Februar 19, 2021 - Lesezeit: ~1 Minute

Bei Excel wird bei den Trennoperatoren ein Unterschied zwischen der Oberfläche und Quellcode in Open.Xml gemacht.

QuellCode:

   SUM(A1 , A2)

Oberfläche:

   SUM(A1 ; A2)

In der Öberfläche wird ein Strichpunkt (;) erwartet. Im Quellcode ein Komma (,).


Cover Image

"Man sieht ihnen ihren Zeilenumbruch gar nicht an."

Textdateien, Zeilenumbrüche und Betriebssysteme

Februar 10, 2021 - Lesezeit: 5 Minuten

Eine Textdatei ist nicht nur eine der ältesten Möglichkeiten Informationen auf einem PC abzulegen, sondern auch Dateien in einem Format zu speichern, dass sich gut zwischen verschiedenen Betriebssystemen übertragen lässt. Die Buchstaben werden mit Hilfe einer Tabelle (z.B. ASCII-Tabelle) in einen Binärcode übersetzt und solange die Gegenseite die Tabelle auch kennt, kann das Ganze wieder zurück übersetzt werden.

Nun ist eine Standard ASCII-Tabelle nicht ausreichend, um die ganzen möglichen Schriftzeichen der Welt aufzunehmen. Ist einfach nicht genug Platz. Also gibt es mehrere Tabellen, für jedes Land quasi eine. Da diese Listen irgendwann nicht mehr ausgereicht haben, beziehungsweise man immer wissen musste, mit welcher Tabelle man die Datei lesen musste und die PCs in immer mehr Bereichen zu Einsatz kommen, gib es auch neue Tabellen, die mehr Zeichen fassen können. Die Textdatei wird dann auch größer, doppelt so groß um genau zu sein. Aber Speicher ist ja heute kein so großes Thema mehr. Zudem hat man sich dazu durchringen können, in bestimmten Fällen in der Datei ein Startzeichen zu hinterlegen, mit dem die Kodierung (Welche Tabelle muss benutzt werden?) durch Auslesen ermitteln kann. Stichwort: Byte Order Mark

Dadurch, dass das Interpretieren der Datei jeweils dem Betriebssystem überlassen wird, kann eine Datei normalerweise unkompliziert zwischen Betriebssystemen hin und hergeschoben und auch bearbeitet werden. Zudem ist für das Bearbeiten solcher Dateien eigentlich immer ein Editor mit an Bord. 

Aber ein kleiner Unterschied kann einen immer mal wieder großen und aufwendigen Suchaufwand verursachen.

Der Zeilenumbruch

Also Cursor nach unten und zurück zum Anfang. Dieses Zeilenende wird in verschiedenen Betriebssystemen auch nicht immer gleich gehandhabt. Während Windows hier die nicht druckbaren Zeichen CR (Carriage return - Wagenrücklauf) und LF (Line feed - Zeilenvorschub) verwendet, wollen UNIX- Derivate (Linux, macOS und so weiter) nur ein LF. Das ist im Normalfall gar nicht so schlimm. Die meisten Texteditoren erkennen einfach den benutzten Zeilenumbruch und nutzen ihn einfach weiter. Problematisch kann die Sache werden, wenn man diese Datei irgendwo im Betriebssystem nutzen möchte und das Programm davon ausgeht, dass der richtige Zeilenumbruch verwendet wurde. Bei Unixdateien muss nur ein Zeichen zum Trennen benutzt werden. Benutzt man eine Windowsdatei bleibt ein nicht druckbares Zeichen übrig: CR.

Programme, die dies nicht berücksichtigen, haben dann ein Zeichen in den Skripten oder Einstellungen, welches Probleme verursachen kann. Wenn man die Datei in Windows erstellt und dazu noch einen Texteditor benutzt, der versucht einem die Arbeit des Zeilenumbruchs abzunehmen und automatisch die Betriebssystemwahl trifft, kann es unter Umständen sein, dass man seinen Fehler beim Übertragen der Datei auf Linux gar nicht bemerkt. Unter Linux könnte es dann komische Fehlermeldungen geben, die beim Betrachten der Datei gar nicht auffallen, weil es ja nicht druckbare Zeichen sind.

Nur LF ohne CR funktioniert auch unter Windows gut, weshalb alle neuen Dateien in meinen Texteditoren immer nur noch direkt mit LF als Zeilenumbruch gespeichert werden. Einmal einstellen und fertig. Das kann eigentlich jeder gute Texteditor. Ansonsten sollte man über ein Alternative nachdenken. Was machen wir aber mit Dateien, die schon irgendwo abgelegt sind und über eine falsche Kodierung verfügen? Klar, man kann die Datei jetzt umständlich in einem Editor der Wahl öffnen, ändern und neu speichern. Das ist aber unter Unix-Systemen ohne grafische Oberfläche unter Umständen ein bisschen aufwändig. Unter Unix gibt es ein tolles Tool für die Kommandozeile, mit dem man (unter anderem) den Zeilenumbruch in einer Zeile für x-beliebig große Dateien ändern kann. Der sed - stream editor. Dieses Tool ist eine Standardausstattung und dürfte in jeder Linuxdistribution immer mit an Bord sein. 

Mit folgender Zeile lässt sich das Zeilenende anpassen:

[sudo] sed -i.bak 's/\r$//' <Dateiname hier>

Kurze Erklärung:
  • sudo : wenn man mal wieder mehr Rechte braucht
  • -i.bak : mach eine Sicherheitskopie mit Dateiende .bak
  • 's/\r$//' : hier passiert die Magie, das s/ für Suche, CR Zeichen zum finden und kein neues Zeichen (//) einfügen
  • dann noch der Dateiname und fertig

Es gibt noch mehr solche tollen Einzeiler für jede Menge Anwendungsfälle.


Cover Image

Mit Node.js gegen den Rest der Welt

Heute: schnell mal was zippen

Januar 26, 2021 - Lesezeit: 6 Minuten

Wenn man mehrere Dateien transportieren will ist es meistens einfacher die Dateien in einer Datei zusammenzufassen. Dazu kann man die Dateien einfache in ein komprimiertes Archiv stecken. Eigentlich ist die Komprimierung dafür gedacht, die Dateigröße auf ein Minimum zu reduzieren und so Speicherplatz sparen zu können. Die Komprimierungsverfahren erzeugen aber Dateien, die erst wieder entpackt werden müssen um benutzt werden zu können. Das funktioniert sowohl bei Dateien wie auch ganzen Ordnern.

Es gibt Verfahren, bei denen wird vor der Ausführung der Datei ein eigenes Entpacken ausgeführt und dann wird die Datei gestartet. Sofern es sich um ein Programm handelt, ist das durchaus ein Möglichkeit. Dieses Verfahren ist in der Demo Szene sehr beliebt. Hier gibt es die Herausforderung möglichst viel Programmlogik in möglichst kleinen Dateien unterzubringen. Diese Verfahren sind sehr kompliziert und meist nur für den aktuellen Fall geeignet und machen teilweise von Systemlücken gebrauch, die unter Umständen vom Betriebssystemhersteller auch mal korrigiert werden, was dafür sorgt, dass im nächsten Moment ein entpacken nicht mehr möglich ist oder das Programm funktioniert nicht mehr korrekt. Jetzt gibt es aber auch Verfahren, die genormte Komprimierungs-technologien verwenden und keine Lücken nutzen, dafür nicht immer ganz so effektiv sind. Für unsere Anforderung ganze Verzeichnisse in einer Datei zu transportieren, fällt das aber nur gering ins Gewicht.

Jetzt kann man das Ganze von Hand manuell über Systemtools oder mithilfe vorhandener Software lösen. Hat man die Anforderung aber öfter, sagen wir mal man macht täglich Releases, dann darf der Vorgang gerne automatisiert werden. Das lässt sich in vielen Programmiersprachen sehr komfortabel erledigen. So auch in JavaScript und Node.js. Node.js stellt hierbei die Dateifunktionen und die Pakete und JavaScript macht das Ganze schön flexibel. Gerade wenn z.B. der Dateiname automatisch aus einem Datum erzeugt werden soll, macht einem JavaScript das Leben einfach.

Das Ganze in ein Skript gepackt könnte dann so aussehen:

const path = require('path');
const zipFolder = require('zip-folder'); // npm install zip-folder

// make some nice name
const filenameToUse = new Date().toLocaleString().replace(/\:/g'-');

(async () => {
  zipFolder(
    path.join(__dirname, 'FolderToZip'),
    path.join(__dirname, filenameToUse + '.zip'),
    (err) => {
      if (err) {
        console.log(`oh no! Error while create: ${filenameToUse} `, err);
      } else {
        console.log(`EXCELLENT: ${filenameToUse} created`);
      }
    })
})();

Das Ganze kann man z.B. ja auch noch mit einem ftp Upload kombinieren. Oder die Datei zum Beispiel danach noch zur Sicherung kopieren. So können hier einfach Schritte automatisiert werden und auch an andere Anforderung schnell und flexibel angepasst werden und das mit einem simplen Texteditor. Und und und...


Cover Image

Mit Node.js gegen den Rest der Welt - Heute Webserver

Webserver in Node.js

November 8, 2020 - Lesezeit: 26 Minuten

Mit Node.js lässt sich JavaScript in einer Konsolenumgebung starten, ohne dass dazu eín Browser notwendig wäre. Das eröffnet ganz neue Möglichkeiten, da so JavaScript aus der Sandbox des Browsers herauskommt und die bisherigen Beschränkungen, wie Dateizugriff und betriebssytemspezifische Abfragen nun entweder direkt möglich sind oder unkomplitziert implementiert werden können. Node.js kommt mit einem Paketverwaltungssytem auf den Rechner. Dieser Manager liefert Zugriff auf eine große Zahl von Paketen, in denen viele Funktionen in Node.js bereits realisiert sind oder Node.js durch z.B. Platform invokes sinnvoll erweitert.

Diese Pakete wiederum können Verweise auf andere Pakete haben, falls sie diese benutzen. Ganz ähnlich zu dem Paketmanager von Debian. Wenn z.B. ein FTP Paket geladen wird, wird im Hintergrund das Paket für den Dateizugriff ebenfalls installiert. Mithilfe einer kleinen Konfigurationsdatei und einem ordnerbasierten Paketmanagement, können verschiedene Versionen auf einem Rechner nebeneinander installiert werden. Dies ermöglicht verschiedene Projekte in verschiedenen Versionständen nebeneinander zu betreiben. Weiterhin ist der Anspruch, auf jedem System lauffähig zu sein und das Prinzip "Write once, run anywhere" passend umzusetzen. Intressant wird es immer dann, wenn man versucht betriebssystemspezifische Implementierungen zu nutzen.

Da Node.js unkompliziert sowohl unter Windows als auch unter Linux verwendet werden kann, ist es naheligend, als JavaScriptentwickler einen Blick zu wagen. Man kann im Gegensatz zu anderen Systemen den Know How Aufbau für eine Skriptsprache minimal halten und schnell Ergebnisse erzielen. Um mit der ganzen Umgebung etwas warm zu werden und weil ich für die Entwicklung einen kleinen Webserver benötigt habe, hab ich das Ganze mal mit einem Nodeskript umgesetzt. Natürlich ist dieser Server nicht vergleichbar mit der voll ausgestatteten Variante eines Symolo Servers, aber für kleine Zwecke ist auch ein solches Skript durchaus hilfreich.

Die Funktion des Skriptes umfasst lediglich das Starten eines Webservers, der eine begrenze Anzahl von Dateien aus einem Ordner und dessen Unterordnern laden kann. Dieses Skript ist nicht für Produktivumgebungen gedacht. So, genug chitchat, los gehts:

const http = require("http");
const path = require('path');
const fs = require('fs');

const HOST = "localhost";
const PORT = 8190;
const HOMEPATH = "dmf";

const requestListener = (requestresponse=> {

  let filePath = './' + request.url;
  if (filePath == './/'filePath = './' + HOMEPATH + '/index.html';
  else filePath = './' + HOMEPATH + request.url;

  filePath = filePath.split('?')[0];

  let extname = path.extname(filePath).split('?')[0]; // filter the queryparams

  let contentType = 'text/html'// set default content type
  switch (extname) {
    case '.js'contentType = 'text/javascript'break;
    case '.css'contentType = 'text/css'break;
    case '.json'contentType = 'application/json'break;
    case '.png'contentType = 'image/png'break;
    case '.jpg'contentType = 'image/jpg'break;
  }

  fs.readFile(filePath, (errorcontent=> {
    if (error) {
      if (error.code == 'ENOENT') {
        fs.readFile('./404.html', (errorcontent=> { // some nice error handling
          response.writeHead(200, { 'Content-Type': contentType });
          response.end(content'utf-8');
        });
      }
      else {
        response.writeHead(500);
        response.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n');
      }
    }
    else {
      response.writeHead(200, { 'Content-Type': contentType });
      response.end(content'utf-8');
    }
  });
};

const server = http.createServer(requestListener);
server.listen(PORTHOST, () => { console.log(`Server is running on http://${HOST}:${PORT}`); });

Ein minimalistischer Server auf nur 50 Zeilen. Natürlich wird hier Gebrauch von einigen Paketen gemacht, die viele der Grundarbeiten bereits erledigen. Trotzdem kann sich das Ergebnis sehen lassen. Dieses Skript, unter und für Windows entwickelt, ist auch aus dem Stand unter Linux und MacOS lauffähig. Da hier Dateizugriffe verwendet werden, ist dieses Skript leider nicht für den direkten Einsatz im Browser verwendbar. Dafür beim nächsten Mal ein Beispiel.