GrandAdmiralThrawn
XP Nazi
|
Grüß euch, Ich hätte eine Frage bezüglich der Verwendung von bsd_glob() auf Win32, weil ich da ein Problem mit Verzeichnisnamen habe. Ich kann nicht den kompletten Code posten, also muß es etwas unvollständiger "Pseudo"code tun. bsd_glob() wird statt dem Perl Builtin verwendet, damit Leerzeichen keine Pattern Delimiter darstellen können. Es wird eine Folderstruktur mit 3 Ebenen abgegrast. Ca. so: use strict;
use File::Glob 'glob';
my(@tree) = glob("E:/Data/*");
foreach $branch (@tree) {
if (-d $branch) {
@leaves = glob("$branch/*");
foreach $leaf (@leaves) {
if (-d $leaf) {
$mtime = stat($leaf)->mtime;
$mtimestamps{$leaf} = $mtime;
$leafcount++;
}
}
}
}
Sinn des ganzen ist die Visualisierung einer bestimmten Folderstruktur, sortiert nach Modification Timestamps. Der Code soll auch auf *nix lauffähig sein, und ich baue sowohl auf Linux als auch Windows, daher Perl. Aber der Punkt ist, daß ich am Sonderzeichen ź hängenbleibe! glob() scheint Verzeichnisse mit diesem Zeichen im Namen einfach nicht zu expanden! Damit wird jeder betroffene Folder einfach übersprungen und fällt unter'n Tisch. Etwas Recherche hat ergeben, daß ź kein Mitglied des ISO-8859-15 Zeichensatzes ist, den mein Windows NT5.2 aber nutzen sollte. Dennoch lassen sich Datei- und Verzeichnisnamen mit ź im Windows Explorer problemlos anzeigen und nutzen. Das scheint mir aber nur in UTF-8 zu existieren, nämlich als [ U+017A]. Oder verwendet Windows in Wahrheit irgendein krankes Hybridencoding a la IRC für Dateinamen?! Andere Zeichen, die in ISO-8859-15 existieren werden problemlos behandelt, so z.B. ø, ©, ç, ¾ und so weiter und so fort. Was soll ich jetzt tun? Echt keine Ahnung wie ich das behandeln sollte. Das Script selbst ist übrigens als UTF-8 ohne BOM encoded, falls das eine Rolle spielen sollte. Danke!
Bearbeitet von GrandAdmiralThrawn am 10.10.2014, 19:08
|
Ringding
Pilot
|
Ich weiß nicht, wie Perl unter Windows das macht, aber grundsätzlich hat Windows für alle (traditionellen) API-Funktionen 2 Varianten: eine, die Strings in UTF-16 versteht, und eine mit 8bit-Strings – Windows-1252 typischerweise in unseren Breiten. Die Funktionsnamen haben jeweils ein W für die 16bit- und A für die 8bit-Variante. Sollte Perl die zweite Variante verwenden, kannst du vermutlich gar nichts machen. Vielleicht einen anderen Perl-Build verwenden?
Unter Unix gibt es dieses Problem nicht, weil Perl-Strings einfach Byte-Strings sind und das OS für alle Filenamen ebensolche liefert und versteht.
|
GrandAdmiralThrawn
XP Nazi
|
Bitte entschuldige meine Unwissenheit, aber "W"? "A"? Ich verstehe nicht.
Darf ich deiner Antwort entnehmen, daß Windows hier ein Hybrid Encoding (CP1252+UTF-16) nutzt, um Dateinamen zu kodieren?
Wo Perl ist, muß es doch einen Weg geben..
|
Ringding
Pilot
|
Wenn eine API-Funktion z.B. FindFirstFile heißt, dann existiert dieser Symbolname gar nicht wirklich, sondern stattdessen gibt es FindFirstFileA und FindFirstFileW für die 8- bzw. 16bit-Version. Und nein, Windows verwendet nie ein Hybrid-Encoding für Filenamen, sondern immer UTF-16. Nur über den Weg der API-Funktionen, die von Programmen aufgerufen werden, geschieht hier eine Verwurschtung, und das auch nur dann, wenn die A-Varianten verwendet werden – welche aus diesem Grund heutzutage einfach nicht mehr zeitgemäß sind. Mit http://www.dependencywalker.com kann man sich anschauen, welche Symbole ein .exe oder eine .dll importiert.
|
GrandAdmiralThrawn
XP Nazi
|
Ich glaub ich geb's auf. Es gibt Module, die können z.B. UTF-16LE Dateinamen bzw. Metadaten durch Nutzung der richtigen API Calls einlesen (Win32API::File) und selbst das Core readdir() kanns, aber selbst so simple Core-Geschichten wie ein "Ist das Element ein Verzeichnis?" failen..
Also z.B. if (-d $leaf) geht auch schon nicht mehr...
Das is echt ein Saudreck..
Bearbeitet von GrandAdmiralThrawn am 10.10.2014, 10:53
|
murcielago
Dr. Doom
|
Und wenn du nicht die Perl-Funktion für "sag mir ob das ein Verzeichnis ist" aufrufst, sondern unter Windows eine Weiche hast, welche direkt die Windows-API funktionen aufruft? Ich weiß nicht ob das mit Perl möglich ist, aber das wäre mein Ansatz bei so einem PRoblem
|
GrandAdmiralThrawn
XP Nazi
|
Ich verstehe nicht was du meinst. Wo soll die Weiche implementiert sein? So wie ich das verstehe, sitzt im Perl Core (oder im Perl Modul, wenn man ein solches verwendet) der API Call drin. Man müßte schon das Modul oder den Core umschreiben und rekompilieren fürchte ich?!
Ich glaub kaum, daß ich allen Perl Modulen und dem Core einfach aufzwingen kann, global nur mehr Wide Calls aufs NTFS abzusetzen..
Bearbeitet von GrandAdmiralThrawn am 10.10.2014, 10:59
|
murcielago
Dr. Doom
|
Sagen wir so: in jeder PRogrammiersprache die ich bis jetzt verwendet habe, war es möglich nicht den eigenen Wrapper (was dieser Perl-API-Call ja ist) zu verwenden, sondern einen System-Call abzusetzen auf das darunterliegende OS.
PseudoCode: "if (WIN32APICall(checkmirdasverzeichnis) == true)"...
Verstehst du worauf ich hinauswill?
|
GrandAdmiralThrawn
XP Nazi
|
Selbst den API Call absetzen. Ok. Verstehe. Mal schaun ob das geht, und wie.
|
murcielago
Dr. Doom
|
|
GrandAdmiralThrawn
XP Nazi
|
Hmm, eher [ hier], so scheint es. Aber auf einen grünen Zweig mußt da auch erst Mal kommen. Neben Dirchecking brauchts ja auch noch das Auslesen von Timestamps. Die Ordner listen und in einen Array reinholen geht z.B. schon Mal mit readdir(). Habs im :raw Modus gelesen, damit da nur ja keine automatischen Konversionen passieren. Dennoch scheint das was ich bekomme irgendwie kein UTF-16le zu sein, sondern immer was anderes, wirkt eher wie UCS-2?! Scheinbar ist das En-/Decoding von Dateinamen generell eine Schwachstelle in Perl (meinen zumindest einige Leute im Netz). Langsam treibt mich das jedenfalls in den Wahnsinn! Edit: Ok, es scheint, als würde readdir() besagte Folder zwar einlesen, aber als CP-1252 statt UCS-2le. Geh bitte...
Bearbeitet von GrandAdmiralThrawn am 10.10.2014, 13:16
|
murcielago
Dr. Doom
|
Ja, das ist leider oft ein Graus... ich hab mal Plugins programmiert, welche auf OSX und Win für Adobe Indesign laufen sollten... da drehst durch
|
GrandAdmiralThrawn
XP Nazi
|
Ok, hier kommt die Saugeilheit! Und du hast mich zumindest teilweise drauf gebracht! In Perl 5.8.1 wurde ein Switch disabled ("-C"), mit dem man Perl erklären kann, bitte nur WIDE API Calls aufs Filesystem abzusetzen. Angeblich wurde er entfernt, weil das eh keiner benutzt haben soll (he, super Grund!!). Also hab ich echt Mal ein steinaltes Perl 5.6 installiert, das Skript mit Parameter -C für Perl gestartet und siehe da, es funktioniert.. Wie DUMM ist das bitte?! Edit: Die API Calls selbst aus der kernel32.dll aufzurufen [ geht übrigens auch], aber das will glaube ich wirklich keiner, wenn ich mir das so anschau.
|
Nico
former person of interest
|
kannst ja den verantwortlichen "reporten", vielleicht kommt das "feature" dann zurück.
|
murcielago
Dr. Doom
|
Edit: Die API Calls selbst aus der kernel32.dll aufzurufen [geht übrigens auch], aber das will glaube ich wirklich keiner, wenn ich mir das so anschau. Aber vielleicht gibts dafür wieder selbst gecodete Wrapper irgendwo in den Weiten des Netz
|