Ékezetes fájlnév vs Java

Szerintem minél gyorsabban töröljük az ilyen fájlt, annál jobb. De azért kicsit keresgéltem, és azt véltem hallani, hogy egy sun.jnu.encoding nevű beállításnak is van valamilyen szerepe az ügyben.

Hozzászólások

Szerkesztve: 2024. 11. 22., p – 19:10

Kizárt, hogy nem lesz vele probléma. Ha nem most akkor majd 20 év múlva.

Ja, hogy "jól" kellene?! Mindig is éreztem, hogy felesleges a sok bonyolítás, kódkészletek, unikód, konverzió, normalizáció, mifene, ahelyett, hogy egyszerűen "jól" megcsinálnánk. (Meg is kérdezem mindjárt az éjjájjt, van-e javaslata.)

Hát ez jogos. A gond inkább ott van, hogy azon a derék diszken nem stringek vannak, hanem bájtok. Ráadásul a metaadatok (pl. fájlnevek) minden normális gondolkodású szakmabelinél ASCII-ben voltak értelmezendők. [Jó, igaz, mainframe-en EBCDIC-ben.]

Aztán 199x-ben jöttek a Nyomasek Bobók, és kitalálták a "Kedves Jocó bácsi!.docx" szerű fáljneveket (igen, a szöveg első sora lett a fájlnév), de akkor még unikód sem nagyon volt, hanem mindenféle egyéni lelemény szerint kódolták a jeleket (persze nemcsak a fájlok nevébe, hanem a fájlok tartalmába is, de szerencsére az OS-t a fájlok tartalma nem érdekli, másrészt arra van iconv, recode, stb).

És az miért érdekes, hogy hogyan van tárolva a lemezen? Engem, mint user nem érdekel és nem is kell, hogy érdekeljen, hogy az a szöveg, amit én átadtam a gépnek az hogyan van reprezentálva a felszín alatt. ASCII alatt meg te valójában nem az ASCII táblát érted, hanem a latin karaktereket. A világnak csak 40%-a használ latin karaktereket, de ennek is csak egy szűkebb része éri be az A-Za-z halmazzal. Ki kellene már húznia az IT szakmának a fejét a saját seggéből és a saját mesterségesen generált limitációitól.

- UNICODE 1.0 1992-ben jött létre, fejlesztése 1987-ben kezdődött.

- UTF-8 előzör 93 januárjában lett bemtatva, 98 janurjától az IETF is adoptálta.

Bizonyos mértékig a kívánságod teljesül: amit a TVC-n vagy Windows-ban vagy Applen elmentesz ékezetes-emojis fájlnéven, azt nagy valószínűséggel ugyanazon a gépen ugyanúgy meg fogod találni (ha nem volt semmilyen konfigurációs változás, mondjuk a mount-opcióknál).

Namostan viszont ha a világ többi részével is kapcsolatba akarsz kerülni (interneten, floppyn, postagalambbal), akkor persze lesznek problímók. (Ezt a szót egy Enterprise128 -> TVC migráció során tanultam; de az is jó rész volt, amikor valaki megtudta, hogy az állam szerint neki tűzvürüs színű autója van.)

PS: Az ASCII-ról itt lehet olvasgatni: https://hu.wikipedia.org/wiki/ASCII kezdetnek annyi, hogy a 95 látható karakter van benne (de nem azért, hogy ezek bármelyikét használhassuk a fájlnevekben).

Most mennyire vegyem komolyan a hozzászólásod, amikor egy április elsejei RFC-t hozol fel ellenpéldának?

de nem azért, hogy ezek bármelyikét használhassuk a fájlnevekben

Miért nem? Linuxon 1, Windowson 9 látható karakter tiltott a fájlnévben. Ki tiltja meg, hogy használjam az összes többit?

Továbbra sem az a baj, hogy milyen karaktereket használhatsz fájlnevekben. A karakterek azok absztrakt dolgok, a legteljesebb katalógusuk az Unicode szabvány, de vannak olyan komponensek a számítógépes világban, amelyek nem használják ezt a karakterkészletet, mert legacy dolgok, és a kompatibilitás megtartása miatt nem frissítik őket, hogy Unicode karaktereket kezeljenek.

Aztán amikor ezt az absztrakt dolgot a számítógépek által kezelt primitív adattípusaival kell leképezni, akkor nem marad más, minthogy valamilyen szabályt alkossunk rá, hogy bytesorozatokká képezzük - ezek a karakterkódolások. Ugyanis a számítógépek által kezelt adattípusok kétfélék: valamilyen egész típusok vagy valamilyen lebegőpontos típusok, más adattípust natívan egyik számítógép sem kezel. Az absztrakt "karakter" fogalom egyiknél sincs jelen.

Így marad az, hogy valamilyen egész típusok sorozatára képezzük le a Unicode karakterek sorszámait. És ez nagyon sokféleképpen tehető meg, minden leképezésnek van előnye és hátránya (és akkor még nem beszéltünk a bytesorozatok esetén fellépő endianitási problémáról sem).

Az UTF-8 előnye például az, hogy kompakt reprezentáció, cserébe az egyes karakterek eltérő számú byte-ra képeződnek le. Hasonlóképpen probléma mondjuk az UTF-16 kódolás: ugyan két bájton már egész jól lehet leképezni a Unicode karakterkészlet karaktereit, de sajnos 65536 karakternél többet tartalmaz a Unicode már egy ideje, emiatt a visszafele kompatibilitást figyelembe véve be kellett vezetni a surrogate pair fogalmát. Amit vagy jól kezel egy legacy szoftver (amelyik feltételezte, hogy egy Unicode karakter az egy absztrakt dolog, és nem mindig 2 UTF-16 karakter), vagy rosszul (amelyik simán elvágja a szöveget egy surrogate pair közepén).

Persze, ott van az UTF-32 kódolás, ami feltehetőleg elég karaktert támogat úgy, hogy minden karakter mindig pontosan 4 byte-on elférjen. De ez meg sok esetben pazarlás - pazarlás tárhellyel, memóriával, sávszélességgel. Egy kizárólag angol nyelvű ábécé karaktereit tartalmazó szöveg tárolása UTF-32-ben pazarlás.

És akkor még csak ott tartunk, hogy Unicode karakterkészlet támogatása és leképezése bytesorozattá.

És akkor jön még az, hogy az egyes alkalmazások sokféle módon kaphatnak bemenetet:

  • környezeti változóból
  • parancssori argumentumból
  • felhasználói inputról
  • más program kimenetét olvasva
  • más program által létrehozott fájlt olvasva
  • vadabb programoknál közvetlenül billentyűzet által generált kódokat olvasva (kihagyva mindenféle IME-t, billentyűzetkiosztási beállítást stb.)

És ezek mind-mind bytesorozatok csak (hiszen csak ezt a típust támogatja a CPU).

Minden esetben más és más a módja annak (ha egyáltalán létezik rá mód), hogy megkapjuk az a metaadatot, hogy ezen bemeneteken milyen karakterkódolással vannak reprezentálva az Unicode karakterei.

Az olyan emberi dolgokat, mint jobbról balra, vagy fentről lefelé írás, már hagyjuk is.

Amikor meg azt mondják az Unix zsenik, hogy a text az egy univerzális interfész, jó nagyot hazudnak. A szöveg kezelése nagyon komplex dolog - mert a visszafelé kompatibilitás egy fontos téma.

A programozókat is oktatni kellene arról, hogy hogyan kell jól szöveget kezelni - de mivel komplex téma, és ritkán fontos, kevesen foglalkoznak vele jól. Próbáld meg megmagyarázni egy magyar piacra dolgozó könyvelőprogram fejlesztőjének, hogy nem, nem elég az ISO 8859-2, mert a magyar karaktereken kívül is létezik világ. Ez lesz számára a prioritási lista ezredik eleme, sokkal fontosabb, hogy a megfelelő jogszabályok kezelése benne legyen határidőre a programban. Az Unicode támogatása és az ezzel járó komplex problémák kezelése az ráér.

Többről van itt szó. Például arról, hogy a shell miként adja át az adatokat.

Érdemes elolvasni ezt: https://stackoverflow.com/questions/5408730/what-is-the-encoding-of-argv

 

On Unixes, the argv has no fixed encoding:

a) File names inserted by tab-completion/globbing will occur in argv verbatim as exactly the byte sequences by which they are named on disk. This is true even if those byte sequences make no sense in the current locale.

b) Input entered directly by the user using their IME will occur in argv in the locale encoding. (Ubuntu seems to use LOCALE to decide how to encode IME input, whereas OS X uses the Terminal.app encoding Preference.)

This is annoying for languages such as Python, Haskell or Java, which want to treat command line arguments as strings. They need to decide how to decode argv into whatever encoding is used internally for a String (which is UTF-16 for those languages). However, if they just use the locale encoding to do this decoding, then valid filenames in the input may fail to decode, causing an exception.

Igen, értem én, hogy a világ bonyolult és sok a szürke zóna. Viszont nekem még mindig úgy tűnik, hogy a root cause továbbra is az, hogy 50 év után még mindig probléma egy istenverte string kezelése. Még pontosabban: hogy végre végre eljussunk oda, hogy egy random byte kupacra mutató pointer az nem egy kurva string, hiába próbálja a C annak eladni és ezt a gyökérséget 52 év alatt nem sikerült túlhaladni.

Hát, a számítógép az utasítások szintjén nem kezel stringeket rendesen, csak random bytekupacokat.

A stringek kezelése nehéz. Mert emberi dolgot akarsz modellezni, olyat, ami kultúrafüggő. Egyáltalán, milyen betűk vannak a világban? Ezen betűket hogyan akarjuk számítógépen kódolni? Lehet-e ezt többféleképpen csinálni (igen, lehet). És nincs mérnökileg egyértelműen legjobb megoldás erre. Vannak olyanok, amelyek bizonyos körülmények között jobbak, mint máskor.

Még a számábrázolásban is ez van. Az IEEE 754 szabvány szerinti lebegőpontos ábrázolás csak egy lehetséges ábrázolása a valós számok egyfajta közelítésének. Van, amikor a fixpontos ábrázolás jobb. Van, amikor pedig a BCD ábrázolás hasznos. Ez sem egy egyértelmű dolog. Sőt, még az sem teljesen egyértelmű, hogy egy bináris lebegőpontos számot hogyan kell szépen emberi felhasználásra tízes számrendszerbeli ábrázolásra hozni, erre még két éve is jött ki új algoritmus: https://fmt.dev/papers/Dragonbox.pdf

Szóval nem, nem olyan triviális dolog ez, ha az ember rendesen belegondol.

Persze, felületesen lehet azt mondani, hogy hát ez könnyű, csak amikor az ember elkezd vele igazán dolgozni, akkor derül ki, hogy nem könnyű.

Jó, de engem, mint user miért kellene, hogy érdekeljen, hogy hogyan reprezentálja a stringem a számítógép? Leaky abstraction. Teljesen a lovon fordítva ülés esete, hogy azt várjuk, hogy az user byte kupacként gondoljon egy szövegre, mikor ő szöveget adott át. Igen, tisztában vagyok azzal, hogy vannak nehézségek. De az, hogy egy őskorszakban kialakult szokást úgy kezelünk, mint etalon és egy istenverte ékezetes karaktertől megijedünk (és akkor még csak el sem hagytuk a latin karakterek világát), csak mert egykoron a byte=karakter volt őskorszaki technikai limitációk miatt, az azért elég gáz. Nem az user van a számítógépért, hanem a számítógép az userért.

Ilyen apróságokat már meg sem említek, hogy valószínűleg azok, akik abból indulnak ki, hogy a C is char-nak hívja, de igazából az sincs kőbe vésve, hogy az a 8 bites ASCII karaktereket jelenti sehol, csak azt, hogy minimum 8 bites.

 Nem az user van a számítógépért, hanem a számítógép az userért.

Ez így van. És az is a userért van, hogy legyenek a dolgok visszafelé kompatibilisek. Mert ha meg ezt dobod el, akkor megint a user ellen vagy.

Tégy igazságot, mi a fontosabb: a visszafelé kompatibilitás, vagy az, hogy a felhasználókat máshol ne érje kellemetlenség, cserébe mindenhol mindig  mindenből frissen kell tartani, konvertálni (akár diszket is, meg mindent), újabb hardvert venni stb.

Amúgy hasonló probléma a színek reprezentálása és ezután reprodukálása is.

Milyen színmodellel dolgozunk? Ha ezt rögzítettük, akkor a modellen belül melyik színtérben dolgozunk? Hány biten ábrázoljuk az egyes komponenseket? 

Ezek mind olyan kérdések, amelyekre nincs egyetlen jó válasz, mert felhasználási módtól függ, hogy mi a legjobb.

Aztán a megfelelő grafikai programok vagy támogatják az összes lehetőséget, vagy nem tudnak minden színt jól ábrázolni és dolgozni vele.

Szerkesztve: 2024. 11. 23., szo – 21:29

Pár teszt után azt mondanám, hogy egyes platformokon számíthat a sun.jnu.encoding a fájlnevek értelmezésénél (AIX/J9), másokon esetleg nem (Java8 a Linuxomon), megint másokon nem lehet felülbírálni az alapértelmezést (Java11 a Linuxomon).

Tkp egy strFileName.getBytes("valami") művelet fut amikor a JVM meghívja a libc-ből az open(2)-t, ahol a "valami" a problémás rész.

Szerk:
További mérések alapján azt mondanám, hogy a tesztelt esetekben

1. A sun.jnu.encoding alapján történik a fájlnevek konverziója String és byte[] között. (Meg talán egyéb esetekben, nem igazán dokumentált ez a feature. Szerk: a parancssori argumentumok értelmezése az egyik ilyen eset.)

2. A sun.jnu.encoding a LC_CTYPE alapján áll be, de egyes platformokon -Dsun.jnu.encoding-gal felül lehet bírálni.

3. Ha a programunkban String és byte[] között konvertálunk charset megadása nélkül (ami rossz szokás), akkor a file.encoding beállítás érvényesül.

4. A file.encoding általában a LC_CTYPE alapján áll be (bár van ahol fixen UTF-8), mindenesetre a -Dfile.encoding-gal felül lehet bírálni.

Van amúgy olyan open(2) wrapper hívás, ami elfogad - Java oldalról - byte[] argumentumot? Én úgy tudom, csak Stringet lehet megadni.

Blog | @hron84

valahol egy üzemeltetőmaci most mérgesen toppant a lábával 

via @snq-