OVH Cloud OVH Cloud

Problème bizarre de compatibilité

6 réponses
Avatar
flipouk
Salut,

J'ai une appli qui crée une chemin à partir d'un package. Elle
fonctionne nickel sous Unix (Linux ou MacOSX) depuis des semaines. Mais
récemment, j'ai ai été obligé de la faire tourner sous Windows et là,
elle plante.

Voici un bout de code qui isole le problème :

------------------------------------------------------------
public class PackToPath {
public static void main(String[] args) {
String sep = System.getProperty("file.separator");
String pack = "com.my.package";
String path = pack.replaceAll("\\.", sep);
System.out.println("Package: " + pack);
System.out.println("Chemin correspondant: " + path);
}
}
------------------------------------------------------------

Sous Linux, pas de problème :
$ java PackToPath.java
$ java PackToPath
Package: com.my.package
Chemin correspondant: com/my/package

Sur la machine Windows, je n'ai pas de compilateur. J'utilise donc le
fichier .class compilé sous Linux. Les deux machines sont en java
1.5.0_05, donc cela ne devrait pas être un problème. Voici ce que cela
donne:
C:\> java PackToPath
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 1
at java.lang.String.charAt(Unknown Source)
at java.util.regex.Matcher.appendReplacement(Unknown Source)
at java.util.regex.Matcher.replaceAll(Unknown Source)
at java.lang.String.replaceAll(Unknown Source)
at PackToPath.main(PackToPath.java:6)

Voici ce que je voudrais avoir:
Package: com.my.package
Chemin correspondant: com\my\package
(c'est-à-dire le chemin avec le file.separator Windows).

D'habitude, je n'ai aucun problème pour faire tourner mes applis java
sous Windows, même quand j'utilise des regexps (et j'en utilise énormément).

Merci pour toute aide.

F.

6 réponses

Avatar
seb666fr2
flipouk wrote:
Salut,


'lut


J'ai une appli qui crée une chemin à partir d'un package. Elle
fonctionne nickel sous Unix (Linux ou MacOSX) depuis des semaines. Mais
récemment, j'ai ai été obligé de la faire tourner sous Windows et là,
elle plante.

Voici un bout de code qui isole le problème :

------------------------------------------------------------
public class PackToPath {
public static void main(String[] args) {
String sep = System.getProperty("file.separator");
String pack = "com.my.package";
String path = pack.replaceAll(".", sep);
System.out.println("Package: " + pack);
System.out.println("Chemin correspondant: " + path);
}
}
------------------------------------------------------------

Sous Linux, pas de problème :
$ java PackToPath.java
$ java PackToPath
Package: com.my.package
Chemin correspondant: com/my/package

Sur la machine Windows, je n'ai pas de compilateur. J'utilise donc le
fichier .class compilé sous Linux. Les deux machines sont en java
1.5.0_05, donc cela ne devrait pas être un problème. Voici ce que cela
donne:
C:> java PackToPath
Exception in thread "main" java.lang.StringIndexOutOfBoundsException:
String index out of range: 1
at java.lang.String.charAt(Unknown Source)
at java.util.regex.Matcher.appendReplacement(Unknown Source)
at java.util.regex.Matcher.replaceAll(Unknown Source)
at java.lang.String.replaceAll(Unknown Source)
at PackToPath.main(PackToPath.java:6)

Voici ce que je voudrais avoir:
Package: com.my.package
Chemin correspondant: commypackage
(c'est-à-dire le chemin avec le file.separator Windows).

D'habitude, je n'ai aucun problème pour faire tourner mes applis java
sous Windows, même quand j'utilise des regexps (et j'en utilise énorm ément).

Merci pour toute aide.

F.



sur la bug database, j'ai trouvé le rapport
http://bugs.sun.com/bugdatabase/view_bug.do?bug_idF26653 (qui n'est
pas un bug). Dans l'évaluation, il est dit, je cite :

As stated in the Pattern documentation, it is necessary to double
backslashes in literals since the source code is first processed by
javac. If the literal escape you want is "" you must therefore use
"\".


En essayant ton code avec "\" à la place de "." il n'y a plus
d'erreur. Donc je pense que c'est la solution à ton problème.

--
Seb

Avatar
Hervé AGNOUX
flipouk wrote:

String path = pack.replaceAll(".", sep);


Comme indiqué dans le javadoc, cette méthode est équivalente à :

Pattern.compile(regex).matcher(str).replaceAll(repl)

Comme indiqué dans le javadoc de
Pattern.compile(regex).matcher(str).replaceAll, il faut faire gaffe que

"Note that backslashes () and dollar signs ($) in the replacement string
may cause the results to be different than if it were being treated as a
literal replacement string. Dollar signs may be treated as references to
captured subsequences as described above, and backslashes are used to
escape literal characters in the replacement string. "

Or, avec windows le "sep" est . Donc ta méthode ne fonctionne pas.

Soit tu négocies avec le , soit tu abondonnes, comme moi, tout usage du
file.separator, finalement assez piégeant au niveau de la compatibilité, et
tu travailles avec File, ce qui te conduiras à faire des choses du style :

String[] items;
File pathfile;

items = pack.slit(".");
pathfile = new File(items[0]);
for (int i = 1; i < items.length; i++)
pathfile = new File(pathfile, items[i]);
String path = pathfile.getPath(); // ou autre.

A+.


--
Hervé AGNOUX
http://www.diaam-informatique.com

Avatar
flipouk
wrote:

En essayant ton code avec "\" à la place de "." il n'y a plus
d'erreur. Donc je pense que c'est la solution à ton problème.


Je n'ai pas pu retester avec Windows, mais sous Linux, cela ne
fonctionne pas. Si je remplace '.' par '\' (ou même '\.') j'ai :
$ java PackToPath
Package: com.my.package
Chemin correspondant: com.my.package

En fait c'est la partie "sep" de l'expression qui foire car mon "sep",
sous Windows, c'est en fait "", or "" c'est précisément le caractère
qui permet l'échappement des caractères spéciaux dans les expressions
régulières !

Je connais 6 systèmes d'exploitation (Linux, Solaris, Irix, MacOSX, BSD
et un peu Windows). Windows est le seul qui présente le problème. Je ne
dis pas merci à celui qui décidé de mettre un antislash comme
file.separator :-)

Merci quand même.

A+

F.

Avatar
flipouk
Hervé AGNOUX wrote:
Or, avec windows le "sep" est . Donc ta méthode ne fonctionne pas.


J'ai fini par me rendre compte de cela en effet. C'est très ennuyeux.

Soit tu négocies avec le , soit tu abondonnes, comme moi, tout usage du
file.separator, finalement assez piégeant au niveau de la compatibilité, et
tu travailles avec File, ce qui te conduiras à faire des choses du style :

String[] items;
File pathfile;

items = pack.slit(".");
pathfile = new File(items[0]);
for (int i = 1; i < items.length; i++)
pathfile = new File(pathfile, items[i]);
String path = pathfile.getPath(); // ou autre.


C'est super sympa de me donner une réponse aussi détaillée. En fait,
j'essaie moi aussi autant que possible de travailler avec des
java.io.File plutôt qu'avec des java.lang.String pour représenter les
fichiers.
Je me suis rendu compte que sous Windows la JVM accepte la création d'un
File comme suit :
File file = new File("/path/to/file");
soit avec des forward slashes, comme sous Unix.
Apparemment, on peut même mélanger des '' et des '/'. Quelque chose comme :
File file = new File("C:path/to/file");
fonctionne !
Ensuite, si l'on demande la représentation sous forme de String de ce
File nouvellement créé, on a (sous Windows) :
String str = file.getAbsolutePath();
System.out.println(str); // C:pathtofile

Bref cela remet les choses dans le bon sens (antislashes sous Windows,
forward slashes sous Unix). Ne penses-tu pas, toi qui a de l'expérience
avec ce genre de problème, que cela peut constituer une solution ? C'est
la solution que j'ai finalement adoptée mais la tienne est beaucoup plus
élégante...

Merci.

F.

Avatar
flipouk
Hervé AGNOUX wrote:
String[] items;
File pathfile;

items = pack.slit(".");
pathfile = new File(items[0]);
for (int i = 1; i < items.length; i++)
pathfile = new File(pathfile, items[i]);
String path = pathfile.getPath(); // ou autre.

Je viens de tester cette solution. Je l'aime bien car elle est élégante,

mais elle va me demander plus de refactorisation de code que de
simplement construire mes File en mélangeant et / :-(

Sinon, j'ai trouvé une petite erreur : java.lang.String.split() prend
une regex comme argument. Donc le '.' est une regex. Pour avoir le '.'
en tant que '.' (et non en tant que sa signification dans une regex qui
est "n'importe quel caractère") il faut écrire :

items = pack.split(".");

Pour info, mon code va être finalement :

----------------------------------------------------------------
public class PackToPath {
public static void main(String[] args) {
String sep = System.getProperty("file.separator");
String pack = "com.my.package";
String[] bits = pack.split(".");
StringBuffer sb = new StringBuffer();
for(int i = 0; i < bits.length; i++) {
sb.append(i != bits.length ? bits[i] + sep : bits[i]);
}
String path = sb.toString();
System.out.println("Package: " + pack);
System.out.println("Chemin correspondant: " + path);
}
}
----------------------------------------------------------------

Sous Linux j'obtiens :
$ java PackToPath
Package: com.my.package
Chemin correspondant: com/my/package/

Et sous Windows :
C;> java PackToPath
Package: com.my.package
Chemin correspondant: commypackage

Merci beaucoup pour ton aide !

A+

F.

Avatar
Hervé AGNOUX
flipouk wrote:


Bref cela remet les choses dans le bon sens (antislashes sous Windows,
forward slashes sous Unix). Ne penses-tu pas, toi qui a de l'expérience
avec ce genre de problème, que cela peut constituer une solution ? C'est
la solution que j'ai finalement adoptée mais la tienne est beaucoup plus
élégante...



A mon avis, si l'on veut être portable, la bonne politique est de ne jamais
utiliser les séparateurs de fichier, du moins dans le code source, donc de
toujours travailler à partir de jeux de File.

Tant mieux si ma solution t'a plu :-)


--
Hervé AGNOUX
http://www.diaam-informatique.com