Hello,
Adott egy konzolos 5 soros program, ami a paraméterben kapott fájlt utf8-ra alakítja. (Egy feldolgozási folyamat végén egy másik programból kerül meghívásra).
Remekül működött a jre 1.8 update 411-ig. Ettől fogva a fájlt csak akkor tudta megnyitni, ha átadtam a jvm-nek a -Dsun.jnu.encoding=utf8 paramétert.
Ismét működött (411-421), de most jött nemrég a 431. És megint nem megy.
Ha nem adok át neki paramétert (-Dsun.jnu.encoding=utf8) akkor jól működik (tehát mint előtte).
Ugye most nézegethetném (valahogy), hogy melyik verzió megy és aszerint hívhatnám meg (A sun.jnu.encoding paramétert nem lehet programból állítani tehát az nem játszik, hogy programon belül lekezelem a kivételt és újra próbálom más paraméterrel).
Várom az ötleteket.
Köszönöm!
f:\test2024>java -Dsun.jnu.encoding=utf8 utf8 KÖN_202410_2411111223.xml
Java Runtime version 1.8.0_421-b09
---------------------------------------------------------
Charset.defaultCharset() = windows-1250
System.getProperty("file.encoding") = Cp1250
System.getProperty("native.encoding") = null
System.getProperty("sun.jnu.encoding") = utf8
System.getProperty("sun.stdout.encoding") = cp852
System.getProperty("sun.stderr.encoding") = cp852
f:\test2024>java -Dsun.jnu.encoding=utf8 utf8 KÖN_202410_2411111223.xml
Java Runtime version 1.8.0_431-b10
---------------------------------------------------------
Charset.defaultCharset() = windows-1250
System.getProperty("file.encoding") = Cp1250
System.getProperty("native.encoding") = null
System.getProperty("sun.jnu.encoding") = utf8
System.getProperty("sun.stdout.encoding") = cp852
System.getProperty("sun.stderr.encoding") = cp852
Exception in thread "main" java.nio.file.NoSuchFileException: K?N_202410_2411111223.xml
at sun.nio.fs.WindowsException.translateToIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsException.rethrowAsIOException(Unknown Source)
at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(Unknown Source)
at java.nio.file.Files.newByteChannel(Unknown Source)
at java.nio.file.Files.newByteChannel(Unknown Source)
at java.nio.file.Files.readAllBytes(Unknown Source)
at utf8.main(utf8.java:25)
Hozzászólások
Kell, hogy javat használj? iconv / recode / uconv (az ICU-féle)? (Igen, ezek *X-en elterjedtebbek, mint Win-en, de ötletet kértél.)
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
Igen, kell. Illetve megírhatnám másban is, de ebben volt kényelmes. Windows-on futó kliens hívja.
A forrást nem teszed fel? Ha már 5 sor?
> NoSuchFileException: K?N_202410_2411111223.xml
Szerintem a parancssorban megkapott paramétert más encoding szerint értelmezi, mint amiben valójában jön. Például azt hiszi, hogy a paraméternek is UFT-8-ban kell jönni, de a Windows valami másban küldi. A paraméter beolvasása Java Stringbe a programod indítása előtt megtörténik, tehát ezzel nem tud a programod semmit se csinálni, ennek jónak kell lenni eleve, különben nem fogja tudni betölteni a fájlt, az a hiba lesz, amit írtál.
Ha biztosra akarsz menni, akkor a bináris ábrázolását a bemeneti paraméternek visszaírod (azért nem a stringet, mert azt meg a terminál is elronthatja, ha félre van konfigolva) a program futása elején, és akkor kiderül, hogy tényleg ez-e a probléma. Belül a Java szerintem már a Windowsnak az U16 API-ját használja, ha egyszer jól van a fájlnév a JVM-ben, akkor már meg fogja tudni nyitni. De az ördög nem alszik...
A megoldást persze nem tudom, nem találkoztam még ilyennel, hogy a parancssori paramétert ne jól olvasta volna ki a Java. A saját programjainkban mindig explicit megadjuk, hogy melyik fájlnak mi az enkódolása, és sose építünk a konfigurált beállításokra. A paraméterek meg eddig mindig jól jöttek, bár tény, hogy többnyire nem is használunk ékezetes fájlneveket, lehet, hogy ki se derült volna, ha ilyen van.
Jogos. Íme a kód.
A probléma csak az ékezetes fájlnevekkel van természetesen. Bennem van még a zsigeri érzés, hogy kerüld az ékezeteket, de 2024-ben ez már ne legyen probléma..
Nem lehet a Charset.defaultEncoding helyett átadni explicite, hogy milyen charset legyen használva? A sun.jnu.encoding azt írja felül, hogy a parancssor milyen encodinggal jön be a processzbe. Lásd: https://happygiraffe.net/2009/09/24/java-platform-encoding/ De lehet, hogy ez nem standard, és ezért megváltoztathatják sima verziók között is a működését.
A Windows ugyanaz a két esetben? Nem a Windows ad át mást? Amit debuggolnék, hogy a Javában kiiratnám binárisan (A String char-jait számérték szerint) az argumentum értékét. Meg csinálnék egy C programot, ami szintén kiírja az argumentumait binárisan. Hogy mégis milyen kódolásban adja át a Windows azt a paramétert?
A Windows ugyanaz, ugyanaz a gép is. Karakterenként végigmenve a kapott argv[0]-án eltér a kettő. Tehát a -Dsun.jnu.encoding=utf8 elrontja ebben az esetben a kódolást. (Enélkül a 431 illetve a 411 előtti verziók működnek).
Még nem adtam fel, de lehet, hogy megírom c-ben.
Szerintem az a verzió a hibás, aminél meg kell adni a plusz paramétert, mert pont az a lényeg, hogy az argumentum átadásnak jól kell működni magától. Mivel a Java API-n String típusú a bemeneti paraméter, amit 16 bites UTF-re alakít belül (logikailag legalábbis), ezért sajnos a bináris eredetihez nem tudsz hozzáférni. El tudom képzelni, hogy a terminálban az ENV változók rosszak, és emiatt téved el a JRE, hogy mégis milyen encoding szerint értelmezze a bemenetet. A JRE8 open source, meg lehet nézni, hogy pontosan mit is csinál a bemenettel.
Alterntív megoldás eszképelni a bemenetet még mielőtt átadnád a programodnak, átnevezni a fájlt (ha már úgyis szkript dolgozik), vagy egy fájlba írni a bemeneti paramétereket ismert enkódolással. Esetleg JVM-et tenni a programka mellé. Sajnos ez mind jelentős bonyolítás.
Messze a legegyszerűbb az lenne, hogy a szkriptet egészítsük ki egy fájlnévékezettelenítő "move Főkábel.txt fokabel.txt" (majd vissza Fókabél.txt-re :-) ?) lépéssel, és a probléma ténylegesen elhárult. Mivel elhangzott, hogy fix nevet kap.
Persze ez kikerülése a problémának, a valódi megoldás megtalálni azokat a környezeti sajátosságokat amik figyelembevételével az ékezetes args tömb korrekten kezelhető.
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
Én is arra jutottam, h a 411 és a 421 a hibás. Mivel alapból 852-es kódlappal készül a fájl ezért fel kellene, hogy ismerje külön paraméter nélkül is.
Mindenképp szívás. A hívó programokhoz is hozzá kell nyúlni biztosan. Meg tesztelni, meg deploy-olni az ügyfelekhez ahol többféle java verzió lehetséges természetesen.
Ez amúgy olyan marginális terület, hogy nem tudok több erőforrást áldozni arra, hogy random verzióváltásoknál még ezt is vizsgáljam. Max. annyit teszek, hogy lekezelem a kivételt és dobok egy üzenetet a usernek, hogy hiba van és nem készült el a fájlt konverzió.
> Még nem adtam fel, de lehet, hogy megírom c-ben.
Újfent tudnám említeni: iconv / recode / uconv. Ezeket már megírták és Windows alatt is futnak.
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
Azért ezt érdekesnek találtam amikor a két nevet összehasonlítottam:
1.
2.
Úgy értem, hogyan változott az "Ö" betű "?" karakterre...
Még nincs aláírásom.
Az ? karakter az Ö betű lenne, ha értelmezni tudná a jvm, hogy milyen encoding-ról van szó. Így valóban teljesül és jogos a NoSuchFileException, de nem értem, hogy két patchset-el arrébb miért nem működik ugyanaz. (Három külön gépen tesztelve következetesen ez a hiba.)
Ne használj ékezetes fájlneveket, a hívó program is lehet a hunyó ill ntfs-en utf-16 a fájlnév kódolás. :-p
Ez jelen pillantban nem megoldás. A hívó program független a jre verzió változásától és ugyazt a fájlt készíti el A vagy B esetben is.
Szerintem első lépésként az argumentumokat kellene UTF-8-ba (*) konvertálni, és a kovertált sztringeket átadni a további feldolgozásra.
(*) vagy amit a java belül használ
tl;dr
Egy-két mondatban leírnátok, hogy lehet ellopni egy bitcoin-t?
Köszönöm, ez jó lehet. Futok egy kört vele.
Szia!
Csak egy ötlet, de lehet, hogy a Compact Strings feature kavar be, próbáld már ki a jvm-et +XX:-CompactStrings paraméterrel indítani a problémás Java verziókon.
Esetleg még debuggerrel meg lehetne nézni, hogy a processz milyen paramétert kapott, a main-ben hogy néz ki, ha lekéred külön az argumentumokat mit mutatnak, valamint, hogy ezek a stringek internal hogy néznek ki.
szerk: egyébként by default UTF16-ban tárolja a stringet a java internal, kivéve ha ez a feature úgy ítéli meg, hogy Latin-1 karakterek vannak benne, mert akkor már csak 1 bájton.
Unrecognized VM option 'CompactStrings'
Lehet, hogy az 1.8-ban nincs még ilyen ?
Szia!
Jól értem az a probléma, hogy amit átadsz paraméterként annak a kódolását nem úgy értelmezi, ahogy szeretnéd?
A parancssor encodeolását érdemes ellenőrizni: chcp
Igen, ez a probléma. A chcp 852-es kódlapot mutat.
Én azt csinálnám, hogy egy bat fájlba beletenném a futtatást és előtte átállítanám a kódlapot. Azért érdemes beletenni egy bat fájlba, mert ha így az egyes kimeneteket is ki tudod irányítani akár külön fájlba is. Például, ha a programban exception esetén az error -ra írsz (pl System.err.println("valami hiba")) és sikeres futás esetén az out -ra (pl System.out.println("valami sikeres")), akkor ezt a bat fájlban a futtatáskor a megfelelő fájlokba vagy képernyőre tudod irányítani.
De persze, lehet máshogy is. Ahogy neked "olcsóbb" a megoldás.
Ha a kódba is kell segítség, keress nyugodtan.
Köszönöm. Amúgy a .bat-nak a leírtakon kívül még az is előnye, hogy könnyen át lehet paraméterezni a dolgokat, ha esetleg az adott ügyfélnél valami nem úgy van. Bár az ügyfélspecifikus megoldásokat irtom tűzzel-vassal ahol csak lehet, néha jól jön, ha gyorsan kell megoldani valamit.
Szívesen!
ui: JVM indítására bevett szokás például a bat fájl. Pontosan azért amit írsz: sok paraméter megadható.